Transcript Slide 1

Object Oriented Programming
Lecture X
Generics and
notes about other enhancements
in Java 1.5
1
Last Lecture
• Improving Performance in Java programs
– small and simple coding advices to reduce time and
space consumption
• Why put effort on that?
– performance always essential, more or less
– to understand the semantics of the language
– to understand what a compiler Java compiler typically
NOT can do
– to understand organization of the virtual machine
2
Today’s Talk
• Enhancements in Java 1.5
– generics
– enhanced for loops
• Other enhancements (to read on your own)
–
–
–
–
auto boxing/unboxing
type-safe enums
Varargs
Annotations
3
Generics
4
The “Problem”
• A short example
List myIntList = new LinkedList();
myIntList.add(new Integer(0));
Integer x = (Integer)myIntList.iterator().next();
• On line 3, we are forced to make a cast
– even though the programmer in this case knows it is a
list of Integers
5
Why casting is enforced
• The cast is essential because
– it is the only way to ensure type safety
– the compiler can only guarantee that an
Object will be returned by the Iterator
• as specified by the Iterator defintion
• So, what is annoying with this?
– Type casting clutter in the code
– If programmer mistaken → run-time error!
6
The core idea of Generics
• If the programmer knows what the contents will
be
– let her be able to specify and express the type used
List<Integer> myIntList = new LinkedList<Integer>();
myIntList.add(new Integer(0));
Integer x = myIntList.iterator().next();
– ... and the type cast is
7
The main advantages
• The introduction of Generics has enabled
us to abstract over types, leading to
– improved readability
• The declaration tells us ”what’s inside”
– improved robustness
• compile-time checks are now possible
– removal of ”unecessary” type casting
8
The abstract meaning of <E>
public interface List<E>{
void add(E x);
Iterator<E> iterator();
}
public interface Iterator<E>{
E next();
boolean hasNext();
void remove();
}
• E is a formal type
parameter in class
definitions
• In the class definition,
it is not said what
concrete type E is
• This is called a
generic declaration
9
How to give meaning to <E>
1.
2.
3.
4.
5.
List<Integer> myIntList;
//compiles ok!
myIntList = new LinkedList<Integer>(); //compiles ok!
myIntList.add(new Integer(0));
//compiles ok!
myIntList.add(new Float(0.0));
//compile error!
Integer x = myIntList.iterator().next();//compiles ok!
1.
myIntlist is a variable, of type List, and with elements of type Integer. (E in
type List myIntList is now bound to Integer)
myIntlist is assigned an instance of LinkedList, only accepting elements of
type Integer. Now E in LinkedList is also bound to type Integer
We add an object of type Integer. This is ok, compiler knows add(E x)
means add(Integer x)
We add an object of type Float. Compiler cannot find specification for
add(Float x), in myIntList, which generate a compile error!
The compiler is informed that next() in Iterator returns E, which it knows
should be Integer ...but when is the bound to Iterator made??
2.
3.
4.
5.
10
One step back again...
public interface List<E>{
void add(E x);
Iterator<E> iterator();
}
public interface
Iterator<E>{
E next();
boolean hasNext();
void remove();
}
Actual type
myIntList = new
LinkedList<Integer>();
public class LinkedList<E>...
implements List<E>,...{
}
11
Subtyping
• Take a look a the following code:
List<String> ls = new ArrayList<String>();
List<Object> lo = ls;
• Is this legal?
12
Subtyping cnt’d
• Let’s add a few more lines of code...
List<String> ls = new ArrayList<String>();
List<Object> lo = ls;
lo.add(new Object());
String s = ls.get(0); // Compile error!!
Trying to assign an
Object to a String
13
Generic subtyping rule
•
Let Banana be a subtype (class or interface) of
Fruit.
Let GType be a generic type (class or
interface) declaration.
Then, GType<Banana> is not a subtype of
GType<Fruit>
•
•
–
We cannot assign: GType<Fruit> = GType<Banana>
14
Introducing Wildcards
• Let’s take an example of ”old-style” code
– a metod for printing Collections
void printCollection(Collection c){
Iterator iter = c.iterator();
while(iter.hasNext()){
System.out.println(iter.next());
}
}
15
Wild cards cn’td
• An attempt of same example in ”new-style”
code:
void printCollection(Collection<Object> c){
Iterator<Object> iter = c.iterator();
while(iter.hasNext()){
System.out.println(iter.next());
}
}
• Code is correct...but it is not so useful!
16
The supertype <?>
• We can define the Collection to be of unknown type by
Collection<?>
• <?> is the supertype of a generic type (a wildcard type)
Collection<String> c = new Vector<String>;
c.add(”hi ho”);
printCollection(c);
void printCollection(Collection<?> c){
Iterator<?> iter = c.iterator();
while(iterator.hasNext()){
System.out.println(iter.next());
}
}
17
Bounded Wildcards
• Our favurite example – Shape
public abstract class Shape{
public abstract void draw(Canvas c);
}
public class Circle extends Shape{
private int x,y,radius;
public void draw(Canvas c){...};
}
public class Rectangle extends Shape{
private int x,y,width,height;
public void draw(Canvas c){...};
}
18
Bounded Wildcards
• These Shapes can be drawn on a Canvas as:
public class Canvas{
public void draw(Shape s);
}
• But now consider a list of Shapes, which we would like to draw:
public void drawAll(List<Shape> s){
Iterator<Shape> iter = s.iterator();
while(iter.hasNext())
iter.next().draw();
}
19
Bounded Wildcards
• We can instead make use of a bounded
wildcard
– since we always deal with subtypes of Shape
public void drawAll(List<? extends Shape> s){
Iterator<? extends Shape> iter = s.iterator();
while(iter.hasNext())
iter.next().draw();
}
20
Restrictions when using
Wildcards
• We are not allowed to assign elements to a
wildcard List like s inside methods:
public void addRect(List<? extends Shape> s){
s.add(0,new Rectangle()); //compile time error!
}
• The reason: the compiler does not know what
the ”unknown” supertype ? of s is!
– the compiler only knows it must extend Shape
21
Generic Methods
22
Generic methods
• Consider that we want a method to copy all
elements from an array to a Collection:
static void fromArrayToCollection(Object[] a, Collection<?> c) {
for(Object o : a) {
c.add(o); // compile time error
}
}
• Remeber the rule for wildcard assigments
– we cannot just shove in any type of Object!
23
Generic methods
• The solution is to create a generic method
static void fromArrayToCollection(T[] a, Collection<?> c) {
for(T o : a) {
c.add(o); // cmpiler is now happy
}
}
• This method is now applicable for a formal
type T whose supertype is <?>
– T will be inferred to be of type <?>
24
Generic methods
• Some examples:
Object[] oa = new Object[100];
Collection<Object> co = new ArrayList<Object>();
fromArrayToCollection(oa, co);// T inferred to be Object
String[] sa = new String[100];
Collection<String> cs = new ArrayList<String>();
fromArrayToCollection(sa, cs);// T inferred to be String
fromArrayToCollection(sa, co);// T inferred to be Object
25
Generic methods
• …some more examples:
Integer[] ia = new Integer[100];
Float[] fa = new Float[100];
Number[] na = new Number[100];
Collection<Number> cn = new ArrayList<Number>();
fromArrayToCollection(ia, cn);// T inferred to be Number
fromArrayToCollection(fa, cn);// T inferred to be Number
fromArrayToCollection(na, cn);// T inferred to be Number
fromArrayToCollection(na, co);// T inferred to be Object
Collection<String> cs = new ArrayList<String>();
fromArrayToCollection(na, cs);// cmpile-time error
26
Enhanced For Loops
27
The for-each loop
• Consider the following printAll example
public void printAll(List<String> s){
Iterator<String> iter = s.iterator();
while(iter.hasNext())
System.out.println(iter.next());
}
• Using a for-each loop, we can get rid of the Iterator
– yields ”less” code and less opportunities for mistakes
28
The for-each loop
• Same example, but now with for-each instead
public void printAll(List<String> list){
for(<String> s:list)
System.out.println(str);
}
• The ’:’ means ’in’ and the for-each loop is interpreted as:
– for each String s in list, do { … }
29
Iterator in nested loops
• Another ’trickier’ example, this example is ok …right?
List suits = ...;
List ranks = ...;
List sortedDeck = new ArrayList();
for (Iterator i = suits.iterator(); i.hasNext(); )
for (Iterator j = ranks.iterator(); j.hasNext(); )
sortedDeck.add(new Card(i.next(), j.next()));
30
Iterator in nested loops
• Same example after bug-fix:
for(Iterator i = suits.iterator(); i.hasNext();){
Suit suit = (Suit) i.next();
for(Iterator j = ranks.iterator(); j.hasNext();)
sortedDeck.add(new Card(suit, j.next()));
}
31
for-each in nested loops
• Same example, now bug free and using for-each loop:
List suits = ...;
List ranks = ...;
List sortedDeck = new ArrayList();
for (Suit suit : suits)
for (Rank rank : ranks)
sortedDeck.add(new Card(suit, rank));
• The compiler takes care of the bounds check for us
32
References
• Generics:
– Gilad Bracha, ”Generics in the Java
Programming Langauge”, http://java.sun.com
• The other Java 1.5 enhancements:
– http://java.sun.com/j2se/1.5.0/docs/
33