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