Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
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 favurite 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); // cmpiler 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);// cmpile-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