CSE 501N Fall ‘06 02: Machine Overview + Fundamental Types

Download Report

Transcript CSE 501N Fall ‘06 02: Machine Overview + Fundamental Types

CSE 501N
Fall ‘09
16: Java Generics
October 27, 2009
Nick Leidenfrost
Lecture Outline
Generic Types
 Generic Methods
 Bounds

 Upper
Bounds
 Lower Bounds

Wildcards
2
The Downside of Casting

In Java, we use class casts to assign objects to
a more specific type
Hashtable students = new Hashtable();
...
Integer studentID = new Integer(4453563);
string studentName = “Bing Slothersby”;
students.put(studentID, studentName);
...
String name = (String)students.get(studentID);

In a perfect world, having to perform this cast is
only mildly annoying, but…
3
The Downside of Casting

… in reality, it is just one more place for
programmer error.
Hashtable students = new Hashtable();
...
Integer studentID = new Integer(4453563);
students.put(studentID, studentID);
...
/* Class Cast Exception */
String name = (String)students.get(studentID);

Wouldn’t it be nice if the compiler could
check for things like this?
4
Type Variables

Generic programming: creation of programming
constructs that can be used with many different types
 In Java, achieved with inheritance -or- with Type
Variables

For example:
 Inheritance vs. Type variables: a LinkedList
(e.g. LinkedList<String>)
5
Type Variables: Generic Classes

Generic class: a class declared with one or
more type variables
public class LinkedList<E> {
// could have used "ELEMENT_TYPE" or other name
// name instead of E
public LinkedList() { . . . }
public void add(E element) { . . . }
. . .
}

The type variable denotes the element type
Continued
6
Type Variables

Can be instantiated with class or interface types
LinkedList<BankAccount>
LinkedList<Comparable>

Cannot use a primitive type as a type variable
LinkedList<double> // Wrong!

Use corresponding wrapper class instead
LinkedList<Double>
7
Type Variables


Supplied type “replaces” type variable in the class
interface
Example: add in LinkedList<BankAccount>
has type variable E “replaced” with BankAccount:
public void add (BankAccount element)

Contrast with LinkedList.add:
public void add (Object element)
8
Type Variables Increase Safety

Type variables allow the compiler to
perform some compile-time checks to
ensure the correct type is being used

Unlike when implemented with inheritance
it is now impossible to add a String into
an LinkedList<BankAccount>
9
Type Variables Increase Safety

Can add a String into a non-generic
collection intended to hold bank accounts
ArrayList<BankAccount> acc1 = new ArrayList<BankAccount>();
ArrayList acc2 = new ArrayList(); // Should hold BankAccounts
accounts1.add("my savings"); // Compile-time error
accounts2.add("my savings"); // Not detected at compile time
. . .
BankAccount account = (BankAccount)acc2.getFirst();
// Run-time error (ClassCastException)
10
Generic Types

Interfaces can be generic too!
public interface Iterator <T> {
public T next ();
public boolean hasNext();
}
11
Type Variable Names


Like classes and variables, Type Variables have
naming conventions
Type Variable
Name Meaning
E
Element type in a collection
K
Key type in a map
V
Value type in a map
T
General type
S, U
Additional general types
In longer type names, lower-case letters should
be avoided in type variables to avoid confusion
with class names and normal variables
12
Implementing Generic Classes

Example: simple generic class that stores
pairs of objects
Pair<String, BankAccount> result
= new Pair<String, BankAccount>("Harry Hoo", checking);

The getFirst and getSecond retrieve
first and second values of pair
String name = result.getFirst();
BankAccount account = result.getSecond();
13
Class Pair
public class Pair<T, S> {
private T first;
private S second;
public Pair (T firstElement, S secondElement) {
first = firstElement;
second = secondElement;
}
public T getFirst() { return first; }
public S getSecond() { return second; }
}
14
Implementing Generic Classes





Generics are particularly useful for collections
Use Type Variables when you receive, return, or
store an element
Complexities arise only when your data structure
uses helper classes, e.g. Nodes, KeyValuePairs,
MapItems, etc.
If helpers are inner classes, no need to do
anything special
Helper types defined outside generic class need
to become generic classes too
public class ListNode<E>
15
Turning LinkedList into a Generic Class
public class LinkedList<E> {
private Node<E> head;
}
public E removeFirst() {
if (this.isEmpty())
return null;
E element = head.next.contents;
head.next = head.next.next;
head.next.prev = head;
public class Node<E> {
return element;
}
E data;
Node<E> next;
}
16
Generic Assignability

We must not think of generic objects as having
similar properties to class hierarchies:
LinkedList<String> stringList = new ArrayList<String>();
LinkedList<Object> objectList = stringList;
We now have an alias of type
 Type Variable bounds
and wildcards
LinkedList<Object>
that wouldwill let
an Object
to
be
inserted
into a
do this to someallow
extent
in
a
more
type-safe
LinkedList<String>!
us
manner
17
Generic Methods



Generic method: method with a type variable
Can be defined inside ordinary and generic
classes
A regular (non-generic) method:
public static int sum (int[] array) {
int sum = 0;
for (int num : array)
sum += num;
return sum;
}
18
Generic Methods

What if we want to sum an array of
doubles instead?
public static <E> void sum (E[] array) {
E sum;
for (E element : array)
sum += element;
return sum;
}
19
Generic Methods

When calling a generic method, you don’t
need to specify the type variables:
Rectangle[] rectangles = . . .;
ArrayUtil.print(rectangles);

The compiler deduces that E is the class
Rectangle
 (You can also define generic methods that are
not static)
20
Generic Methods
You can even have generic methods in
generic classes
 Cannot replace type variables with
primitive types

21
Syntax: Instantiating a Generic
Class
modifiers <TypeVariable1, TypeVariable2, . . .>
returnType methodName (parameters) {
// method body
}
Example:
public static <E> void print(E[] a) {
// Method body
}
Purpose:
To define a generic method that depends on type variables
22
Constraining Type Variables

Type variables can be constrained with
bounds
public static <E extends Comparable> E min(E[] a) {
E smallest = a[0];
for (int i = 1; i < a.length; i++)
if (a[i].compareTo(smallest) < 0) smallest = a[i];
return smallest;
}
23
Constraining Type Variables

Can call min with a String[] array but not
with a Person[] array

Comparable bound necessary for calling
compareTo

Otherwise, min method would not have
compiled
24
Constraining Type Variables

Very occasionally, you need to supply two
or more type bounds
<E extends Comparable & Cloneable>



extends, when applied to type variables,
actually means "extends or implements"
The bounds can be either classes or
interfaces
Type variable can be replaced with a class
or interface type
25
Wildcard Types
Wildcard types are useful when we want to
allow the broadest set of generic objects to
interact with our generic object
 We may not know (or care) what actual
generic type is contained within the object we
are dealing with

 As
long as the generic type of the object we are
dealing with matches our criteria
26
Wildcard Types
Name
Syntax
Meaning
Wildcard with lower bound
? extends B
Any subtype of B
Wildcard with upper bound
? super B
Any supertype of B
Unbounded wildcard
?
Any type
27
Wildcard Types
public void addAll(LinkedList<? extends E> other) {
ListIterator<E> iter = other.listIterator();
while (iter.hasNext()) add(iter.next());
}
public static <E extends Comparable<E>> E min(E[] a)
static void reverse(List<?> list)
28
Wildcard Types: ? extends T



Determines an “upper bound” in the inheritance hierarchy
for what the actual type could be
Writing non null elements is not allowed
 Why? Because we don’t know what type is contained
 List<? extends Animal> could be a
List<Animal> or a List<Dog>, and we can’t put an
Animal into a List<Dog>
Useful when we need to “read” from a generic typed object:
public void emptyAndProcess (LinkedList<? extends T> list) {
T listItem = list.removeFirst();
// Do something with T
}
29
Wildcard Types: ? super T



Determines an “lower bound” in the inheritance
hierarchy for what the actual type could be
Reading from such a list returns data of type Object
Useful when we need to “write” to a generic typed
object:
public void add (LinkedList<? super T> list, T toAdd) {
list.add(toAdd);
}
30
Raw Types

The virtual machine works with raw types,
not with generic classes
 Once
compiled, any detectable type
incompatibility problems have necessarily
been eliminated

The raw type of a generic type is obtained
by erasing the type variables
 “Type
erasure”
31
Raw Types

For example, generic class Pair<T, S>
turns into the following raw class:
public class Pair {
private Object first;
private Object second;
public Pair(Object firstElement, Object secondElement) {
first = firstElement;
second = secondElement;
}
public Object getFirst() { return first; }
public Object getSecond() { return second; }
}
32
Raw Types

Same process is applied to generic
methods:
public static Comparable min (Comparable[] a) {
Comparable smallest = a[0];
for (int i = 1; i < a.length; i++)
if (a[i].compareTo(smallest) < 0) smallest = a[i];
return smallest;
}
33
Raw Types

Knowing about raw types helps you
understand limitations of Java generics

For example, you cannot replace type
variables with primitive types

To interface with legacy code (non-generic
code), you can convert between generic
and raw types
34
Conclusion

For additional reading on Generics:
 http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf
Questions?
 Lab 6 Assigned today
 Due 11/03

35