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
1. Standard Java Collections Framework 2. Java 5 “Tiger” features 1 Outline 1. CASE : Java Collections (JCF) Introduction the Object interface (“contract”) Object equality Object hashing Iterators Collection framework Collections Maps 2. Java 5 “Tiger” features 2 Introduction Collection is used to hold Object references different Collection types ordering : remember insertion order ? duplicates allowed (what is a duplicate ?) single Objects or pairs of Objects (“associative array”) efficiency/performance until Java 1.4 : programmed to Object-interface very extensible many casts required from Java 1.5 (“Java 5, Tiger”) : generics easy to use generics tricky to program own generic types 3 Introduction 4 Object interface Offered to ALL Objects ! public String toString() public boolean equals(Object o) public int hashCode() public Class getClass() public public public public public void void void void void notify() notifyAll() wait() wait(int i) wait(int i,long l) 5 Object interface Default implementation : based on Object references public String toString() <Class>@<reference> public boolean equals(Object o) two Objects are identical if references are equal heavily used in Collections framework ! (check on duplicates !) default equals identical to == operator on references public int hashCode() int based on Object reference equal Objects must have equal references used for high performance Object retrieval 6 Object interface package intro; class A { protected int a=0; public A(int aa) {a=aa;} public A(A oA) {a=oA.a;} public void setA(int aa) {a=aa;} } class Test { public static void main(String[] args) { A a1=new A(1),a2=new A(2),a3=new A(a1),a4=a1; System.out.println("a1="+a1); System.out.println("a2="+a2); System.out.println("a3="+a3); System.out.println("a4="+a4); System.out.println("hash a1="+a1.hashCode()); System.out.println("hash a2="+a2.hashCode()); System.out.println("hash a3="+a3.hashCode()); System.out.println("hash a4="+a4.hashCode()); System.out.println("a1.equals(a2) = "+a1.equals(a2)); System.out.println("a1.equals(a3) = "+a1.equals(a3)); System.out.println("a1.equals(a4) = "+a1.equals(a4)); } 7 Object interface a1=intro.A@eee36c a2=intro.A@194df86 a3=intro.A@defa1a a4=intro.A@eee36c hash a1=15655788 hash a2=26533766 hash a3=14613018 hash a4=15655788 a1.equals(a2) = false a1.equals(a3) = false a1.equals(a4) = true 8 Object equality Fundamental question When are two Objects equal ? - same Object in memory (reference equality) - same Object in “real world” (logical equality) method contains (in Collection interface) signature : public boolean contains(Object o) returns true if argument in the Collection based on equals(Object o) 9 Object equality class A { protected int a=0; public A(int aa) {a=aa;} public A(A oA) {a=oA.a;} public String toString(){return "<A:"+a+">";} public void setA(int aa) {a=aa;} } class TestEqual { public static void main(String[] args){ ArrayList l=new ArrayList(); A a1=new A(1); l.add(a1); System.out.println("Containing a1: "+l.contains(a1)); // true System.out.println("Containing A(1):"+l.contains(new A(1))); // false System.out.println("Containing A(a1):"+l.contains(new A(a1))); // false a1.setA(3); System.out.println("Containing a1:"+l.contains(a1)); // true System.out.println("Containing A(3):"+l.contains(new A(3)));// false } } 10 Object equality class A { protected int a=0; public A(int aa) {a=aa;} public A(A oA) {a=oA.a;} public String toString(){return "<A:"+a+">";} public void setA(int aa) {a=aa;} public boolean equals(Object o) {return ((A)o).a==a;} } class TestEqual { public static void main(String[] args){ ArrayList l=new ArrayList(); A a1=new A(1); l.add(a1); System.out.println("Containing a1: "+l.contains(a1)); // true System.out.println("Containing A(1):"+l.contains(new A(1))); // true System.out.println("Containing A(a1):"+l.contains(new A(a1))); // true a1.setA(3); System.out.println("Containing a1:"+l.contains(a1)); // true System.out.println("Containing A(3):"+l.contains(new A(3)));// true } } 11 The equals contract public boolean equals(Object o) { return ( (A) o).a==a; } Unsafe downcast ! Solution : check type BEFORE downcast ! • requires runtime type identification (RTTI) • Java operator : instanceof o instanceof A true if runtime type is (subtype of) A 12 The equals contract Java idiom for equals(Object o) class A { // ... public boolean equals(Object o) { if(o instanceof A) { // SAFE downcast to type A // code to decide on logical equality // return ... } else return false; } } 13 The equals contract equals(Object o) MUST satisfy : 1. 2. 3. equivalence relation • reflexivity for any x : x.equals(x) ALWAYS true • symmetry for any x and y : x.equals(y) ALWAYS identical to y.equals(x) • transitivity for any x, y and z if x.equals(y) is true AND y.equals(z) is true THEN x.equals(z) should also be true consistency for any x and y : subsequent calls x.equals(y) should give same result if state of x and y used in equals is untouched null condition for any x, different from null : x.equals(null) MUST be false 14 Hashing Objects Hashing • associate int to an Object • purpose : fast Object retrieval • hash code related to “bucket” • look in bucket to see if Object present • properties • identical Objects must have equal hash codes (MUST be in same bucket !) • ideally : hash code equally distributed (all buckets equally filled) - equal hash code does NOT imply equal Objects - hash code algorithm should only use attributes used in equals(Object o) - good practice : override hashCode every time equals is overridden 15 A good hash function ? 1. initialize int result to non-zero value (e.g. 17) 2. compute int c for each attribute f used in equals type of f boolean byte, char, short, int long float double Object only if equals() used on f array c f ? 0 : 1 (int)f (int)(f^(f>>>32)) Float.floatToIntBits(f) long l=Double.doubleToLongBits(f); (int)(l^(l>>>32)) f.hashCode() iterate over all fields 3. add all c-values using result =37*result+c; 4. return result TEST if equal Objects have equal hash codes !!! 16 Hashing A class A { protected int a=0; public A(int aa) {a=aa;} public A(A oA) {a=oA.a;} public String toString(){return "<A:"+a+">";} public void setA(int aa) {a=aa;} public boolean equals(Object o) { if(o instanceof A) return ((A)o).a==a; else return false; } public int hashCode(){ int result =17; int c=a; result = 37*result+c; return result; } } class TestHash { public static void main(String[] args) { A a1=new A(1);A a2=new A(1); System.out.println("Equals : "+a1.equals(a2)); // true System.out.println("Hash code a1 :"+a1.hashCode()); // 630 System.out.println("Hash code a2 :"+a2.hashCode()); // 630 } } 17 Iterators • • • Used to move through Collection No knowledge of underlying data structure needed ! cheap Object ! (fast creation, usage !) Iterator interface boolean hasNext() returns true if the iteration has more elements. Object next() returns the next element in the iteration. void remove() removes from the underlying collection the last element returned by the iterator (optional operation). 18 Iterators ListIterator interface (extends Iterator) void add(Object o) Inserts the specified element into the list (optional operation). boolean hasNext() Returns true if this list iterator has more elements when traversing the list in the forward direction. boolean hasPrevious() Returns true if this list iterator has more elements when traversing the list in the reverse direction. Object next() Returns the next element in the list. int nextIndex() Returns the index of the element that would be returned by a subsequent call to next. Object previous() Returns the previous element in the list. int previousIndex() Returns the index of the element that would be returned by a subsequent call to previous. void remove() Removes from the list the last element that was returned by next or previous (optional operation). void set(Object o) Replaces the last element returned by next or previous with the specified element (optional operation). 19 Iterators Idiom for iterating for(Iterator i=c.iterator();i.hasNext();) { Object o=i.next(); // do something with o } 20 JCF taxonomy (simplified) Collection : any group of Objects Map : (key,value)-pairs 21 Sorts of Collections Collection : any group of Objects List - Ordered (sequence) : positional access - Duplicates allowed Set - No duplicate elements permitted. - May or may not be ordered. SortedSet - Automatically ordered Set 22 Collection interface public public public public public public public boolean add(Object o) boolean addAll(Collection c) boolean remove(Object o) booean removeAll(Collection c) boolean retainAll(Collection c) boolean contains(Object o) boolean containsAll(Collection c) // intersection public void clear() public boolean isEmpty() public int size() public Iterator iterator() no get()-method ! public Object[] toArray() public Object[] toArray(Object[] a) 23 Sorts of Lists general features - produces ListIterator (two-way traversal) - guarantees sequence integrity (positional access) types of Lists ArrayList - internal data structure : array - fast random access - slow for inserting/removing elements LinkedList - linked list implementation - fast for removing/inserting elements - “slow” for random access 24 List interface In addition to Collection : void add(int index,Object o) boolean addAll(int index,Collection c) Object remove(int index) Object set(int index, Object element) Object get(int index) int indexOf(Object o) // search, -1 if not found int lastIndexOf (Object o) ListIterator listIterator() ListIterator listIterator(int index) List subList(int fromIndex, int toIndex) 25 List test class TestList { public static void main(String[] args) { List l=new LinkedList(); fill(l,1000);print(l); long t1=System.currentTimeMillis(); testRandomAccess(l,1000000); long t2=System.currentTimeMillis(); System.out.println("Time elapsed : "+(t2-t1)+" ms."); } public static void fill(List l,int n) { for(int i=0;i<n;i++) l.add(new A((int)(n*Math.random()))); } public static void testRandomAccess(List l,int n) { int index=0; A a=new A(0); for(int i=0,s=l.size();i<n;i++) { index=(int)(Math.random()*s); l.set(index,a); } } public static void print(List l) { for(Iterator i=l.iterator();i.hasNext();) System.out.println(i.next()); } 26 } Sorts of Sets general features - IDENTICAL interface as Collection - no duplicates - ordering : depends on Set type types of Lists HashSet - for fast element lookup - elements must implement hashCode() TreeSet - ordered Set - can be transformed to sequence LinkedHashSet - lookup speed of HashSet - keeps insertion order ! 27 Sorts of Sets class TestSetList { public static void main(String[] args) { List l=new ArrayList(); Set s=new HashSet(); A[] a={new A(1),new A(2),new A(1),new A(2),new A(3)}; for(int i=0;i<a.length;i++) { l.add(a[i]);s.add(a[i]); } System.out.println("list = "+l); System.out.println("set = "+s); } } for HashSet list = [<A:1>, <A:2>, <A:1>, <A:2>, <A:3>] set = [<A:3>, <A:1>, <A:2>] for LinkedHashSet list = [<A:1>, <A:2>, <A:1>, <A:2>, <A:3>] set = [<A:1>, <A:2>, <A:3>] 28 Ordering Objects two options 1. natural ordering class should be Comparable 2. explicit ordering explicit Object of type Comparator specified when ordered Collection is instantiated 29 Ordering Objects : natural ordering The compareTo-contract : x.compareTo(y) 1. return value negative if x<y zero if not x<y and not x>y positive if x>y 2. symmetry sgn(x.compareTo(y)) == - sgn(y.compareTo(x)) (sgn : signum function) 3. transitivity if x.compareTo(y) > 0 AND y.compareTo(z) > 0 THEN x.compareTo(z) > 0 4. relation to == if x.compareTo(y) == 0 THEN sgn(x.compareTo(z)) == sgn(y.compareTo(z)) Consistency with equals() x.equals(y) true <-> x.compareTo(y) == 0 NOT required but highly recommended ! 30 Ordering Objects : explicit ordering Set s=new TreeSet(myComparator); // uses myComparator for ordering THIS set // instead of compareTo of the elements ! • same contract (but now for compare(x,y) ) • equals to check equality of Object o with this Comparator Object 31 SortedSet interface Comparator comparator() // null if natural ordering is used Object first() Object last() // smallest element // largest element SortedSet subSet(Object fromElement,Object toElement) SortedSet headSet(Object toElement) // subset < toElement SortedSet tailSet(Object fromElement) // subset >= fromElement 32 Testing TreeSet class A implements Comparable { protected int a=0; public A(int aa) {a=aa;} public A(A oA) {a=oA.a;} public String toString(){return "<A:"+a+">";} public void setA(int aa) {a=aa;} public boolean equals(Object o) { if(o instanceof A) return ((A)o).a==a; else return false; } public int hashCode(){ int result =17; int c=a; result = 37*result+c; return result; } public int compareTo(Object o) { if (a<((A)o).a) return -1; else if(a==((A)o).a) return 0; else return 1; } } 33 Testing TreeSet class Comp implements Comparator { public int compare(Object x,Object y) { if (((A)x).a<((A)y).a) return 1; else if(((A)x).a==((A)y).a) return 0; else return -1; } } class TestTreeSet { public static void main(String[] args) { SortedSet s=new TreeSet(); SortedSet t=new TreeSet(new Comp()); A[] a={new A(4),new A(5),new A(3),new A(2),new A(1),new A(5)}; for(int i=0;i<a.length;i++) {s.add(a[i]);t.add(a[i]);} System.out.println("natural ordering = "+s); System.out.println("first = "+s.first()); System.out.println("explicit ordering = "+t); System.out.println("first = "+t.first()); System.out.println("headset up to A(3)"+t.headSet(new A(3))); } natural ordering = [<A:1>, <A:2>, <A:3>, <A:4>, <A:5>] } first = <A:1> explicit ordering = [<A:5>, <A:4>, <A:3>, <A:2>, <A:1>] first = <A:5> headset up to A(3)[<A:5>, <A:4>] 34 Sorts of Maps Map : mapping from key to value. A key maps to ONE value at most HashMap constant time performance for search and inserts. LinkedHashMap insertion order kept (slightly slower than HashMap) SortedMap Ordered by keys (either natural or explicit) 35 Map interface void clear() int size() boolean isEmpty() Object get(Object key) // returns value for key specified Object put(Object key, Object value) void putAll(Map m) Object remove(Object key) boolean containsKey(Object key) // true if Map contains entry for this key boolean containsValue(Object value) Set entrySet() // set Object of Map.Entry class Set keySet() // no duplicate keys, so Set is OK Collection values() // duplicate values possible, hence Collection // (instead of Set) 36 Testing Maps class City implements Comparable { protected String name; public City(String n) {name=n;} public boolean equals(Object o) { if(o instanceof City) return name.equals(((City)o).name); else return false; } public int hashCode() { int result =17; result = 37*result+name.hashCode(); return result; } public String toString() {return "<City : "+name+">";} public int compareTo(Object o) { City c=(City)o; return name.compareTo(c.name); } } 37 Testing Maps class Country { protected String name; public Country(String n) {name=n;} public boolean equals(Object o) { if(o instanceof Country) return name.equals(((Country)o).name); else return false; } public int hashCode() { int result =17; result = 37*result+name.hashCode(); return result; } public String toString() {return "<Country : "+name+">";} } 38 Testing Maps class TestMap { public static void main(String[] args) { Map m=new HashMap(); fill(m); System.out.println("Keys : "+m.keySet()); System.out.println("Values : "+m.values()); System.out.println(new City("London")+" is located in : “ +m.get(new City("London"))); System.out.println(new City("Haarlem")+" is located in : “ +m.get(new City("Haarlem"))); } public static void fill(Map m) { m.put(new City("London"),new Country("United Kingdom")); m.put(new City("Birmingham"),new Country("United Kingdom")); m.put(new City("Newcastle"),new Country("United Kingdom")); m.put(new City("Amsterdam"),new Country("The Netherlands")); m.put(new City("Haarlem"),new Country("The Netherlands")); m.put(new City("Eindhoven"),new Country("The Netherlands")); m.put(new City("Paris"),new Country("France")); m.put(new City("Lyon"),new Country("France")); m.put(new City("Marseille"),new Country("France")); m.put(new City("Bordeaux"),new Country("France")); } 39 } Testing Maps : HashMap class TestMap { public static void main(String[] args) { Map m=new HashMap(); // ... } } Keys : [<City : Lyon>, <City : Haarlem>, <City : Newcastle>, <City : Marseille>, <City : Paris>, <City : London>, <City : Amsterdam>, <City : Eindhoven>, <City : Birmingham>, <City : Bordeaux>] Values : <Country <Country <Country <Country [<Country : France>, <Country : The Netherlands>, : United Kingdom>, <Country : France>, <Country : France>, : United Kingdom>, <Country : The Netherlands>, : The Netherlands>, <Country : United Kingdom>, : France>] <City : London> is located in : <Country : United Kingdom> <City : Haarlem> is located in : <Country : The Netherlands> 40 Testing Maps : LinkedHashMap class TestMap { public static void main(String[] args) { Map m=new LinkedHashMap(); // ... } } Keys : [<City : London>, <City : Birmingham>, <City : Newcastle>, <City : Amsterdam>, <City : Haarlem>, <City : Eindhoven>, <City : Paris>, <City : Lyon>, <City : Marseille>, <City : Bordeaux>] Values : <Country <Country <Country <Country [<Country : United Kingdom>, <Country : United Kingdom>, : United Kingdom>, <Country : The Netherlands>, : The Netherlands>, <Country : The Netherlands>, : France>, <Country : France>, <Country : France>, : France>] <City : London> is located in : <Country : United Kingdom> <City : Haarlem> is located in : <Country : The Netherlands> 41 SortedMap interface “Comparable” to SortedSet Comparator comparator() Object firstKey() SortedMap headMap(Object toKey) Object lastKey() SortedMap subMap(Object fromKey, Object toKey) SortedMap tailMap(Object fromKey) 42 Testing Maps : TreeMap class TestMap { public static void main(String[] args) { Map m=new TreeMap(); // ... } } Keys : [<City : Amsterdam>, <City : Birmingham>, <City : Bordeaux>, <City : Eindhoven>, <City : Haarlem>, <City : London>, <City : Lyon>, <City : Marseille>, <City : Newcastle>, <City : Paris>] Values : <Country <Country <Country <Country [<Country : The Netherlands>, <Country : United Kingdom>, : France>, <Country : The Netherlands>, : The Netherlands>, <Country : United Kingdom>, : France>, <Country : France>, <Country : United Kingdom>, : France>] <City : London> is located in : <Country : United Kingdom> <City : Haarlem> is located in : <Country : The Netherlands> 43 EntrySet interface Inner class of Map Represents single (key,value pair) Can be retrieved from Map.entrySet() method boolean equals(Object o) Object getKey() Object getValue() int hashCode() Object setValue(Object value) 44 Testing EntrySet class TestEntrySet { public static void main(String[] args) { Map m=new HashMap(); fill(m); Set s=m.entrySet(); System.out.println(s); System.out.println(new City("Newcastle")+" is located in : “ +m.get(new City("Newcastle"))); for(Iterator i=s.iterator();i.hasNext();) { Map.Entry e=(Map.Entry)(i.next()); if(e.getKey().equals(new City("Newcastle"))) e.setValue(new Country("Belgium")); } System.out.println(new City("Newcastle")+" is located in : “ +m.get(new City("Newcastle"))); System.out.println(s); } public static void fill(Map m) { m.put(new City("London"),new Country("United Kingdom")); m.put(new City("Birmingham"),new Country("United Kingdom")); m.put(new City("Newcastle"),new Country("United Kingdom")); m.put(new City("Amsterdam"),new Country("The Netherlands")); } } 45 Testing EntrySet [<City : Newcastle>=<Country : United Kingdom>, <City : London>=<Country : United Kingdom>, <City : Amsterdam>=<Country : The Netherlands>, <City : Birmingham>=<Country : United Kingdom>] <City : Newcastle> is located in : <Country : United Kingdom> <City : Newcastle> is located in : <Country : Belgium> [<City : Newcastle>=<Country : Belgium>, <City : London>=<Country : United Kingdom>, <City : Amsterdam>=<Country : The Netherlands>, <City : Birmingham>=<Country : United Kingdom>] 46 Outline 1. Java Collections (JCF) 2. Java 5 “Tiger” features auto-boxing – unboxing enhanced for-loop use of generics defining generics 47 Issues with Collections 1. cumbersome and awkward to add/get primitives (need for wrapper types) 2. upcast/downcast to Object awkward (many downcasts necessary) unsafe (downcast inherently unsafe : runtime exceptions !) 3. iterating over Collection bit awkward for(Iteratori=c.iterator();i.hasNext();) { // ... } 48 Conventional add/get to Collection class Main { public static void main(String[] args) { ArrayList i=new ArrayList(); for(int j=0;j<10;j++) { i.add(new Integer(j)); //BOX } System.out.println("Sum of "+i+" = "+sum(i)); } public static int sum(ArrayList l) { int res=0; for(int i=0;i<l.size();i++) { Object o=l.get(i); Integer w=(Integer)o; int j=w.intValue(); //UNBOX res+=j; } return res; } } 49 Using automatic boxing and unboxing Automatic conversion between primitives and associated wrapper types “as needed” (e.g. when adding (autobox) or retrieving (unbox) from Collection) class Main { public static void main(String[] args) { ArrayList i=new ArrayList(); for(int j=0;j<10;j++) i.add(j); // AUTOBOX System.out.println("Sum of "+i+" = "+sum(i)); } public static int sum(ArrayList l) { int res=0; for(int i=0;i<l.size();i++) { Object o=l.get(i); Integer w=(Integer)o; res+=w; // AUTO UNBOX } return res; } 50 } Enhanced for-loop Collection c = ...; // ... for(Object o : c) { // “for all Objects o IN c // do something with o } public static int sum(ArrayList l) { int res=0; for(Object o : l) res+=(Integer)o; // downcast still required ... return res; } Also works on arrays String[] s={"a","b","c","d","f"}; String r=""; for(String i : s) r+=i; 51 Generics Generics concept : Object type is PARAMETER “parameterized types” Heavily used in context of Collections Collection <type> - can only hold <type>-objects - checked statically - programmer gets feed back from compiler (instead of at runtime !) - type only declared in ONE location (improves consistency and clarity) 52 The power of generics class Main { public static void main(String[] args) { Collection<Integer> l=new ArrayList<Integer>(); // only Integers allowed ! // l.add("aaa"); // NOT allowed ! for(int j=0;j<10;j++) l.add(j); // autoboxing + static type check int sum=0; for(Integer i:l) sum+=i; // enhanced for loop // NO explicit iterator // static type check on i (Integer) // Auto-matic unbox System.out.println("Sum of "+l+" = "+sum); } public static int summing(Collection<Integer> c) { int s=0; for(Integer i:c) s+=i; return s; } } 53 Set example : custom type A class A implements Comparable { protected int a=0; public A(int aa) {a=aa;} public A(A oA) {a=oA.a;} public String toString(){return "<A:"+a+">";} public void setA(int aa) {a=aa;} public boolean equals(Object o) {/* as before */} public int hashCode(){/* as before */} public int compareTo(Object o) {/* as before */} public void f() { System.out.println(this+".f()"); } } class Main { public static void main(String[] args) { SortedSet<A> s=new TreeSet<A>(); A[] a={new A(4),new A(5),new A(3),new A(2),new A(1),new A(5)}; for(int i=0;i<a.length;i++) s.add(a[i]); System.out.println("natural ordering = "+s); for(A i:s) i.f(); } } 54 Set example : B extends A class B extends A { public B(int i) {super(i);} public String toString(){return "<B:"+a+">";} public void f() {System.out.println(this+".f()");} } class Main { public static void main(String[] args) { SortedSet<A> s=new TreeSet<A>(); A[] a={new A(4),new A(5),new A(3),new A(2),new A(1),new A(5), new B(1),new B(10),new B(20),new B(-1)}; for(int i=0;i<a.length;i++) s.add(a[i]); System.out.println("natural ordering = "+s); for(A i:s) i.f(); } natural ordering = [<B:-1>, <A:1>, <A:2>, <A:3>, <A:4>, } <A:5>, <B:10>, <B:20>] <B:-1>.f() <A:1>.f() <A:2>.f() <A:3>.f() <A:4>.f() <A:5>.f() <B:10>.f() 55 <B:20>.f() Map example : Cities and Countries class City implements Comparable {/* as before */} class Country { /* as before */} class TestMap { public static void main(String[] args) { Map<City,Country> m=new HashMap<City,Country>(); fill(m); System.out.println("Keys : "+m.keySet()); System.out.println("Values : "+m.values()); System.out.println(new City("London")+" is located in : “ +m.get(new City("London"))); System.out.println(new City("Haarlem")+" is located in : “ +m.get(new City("Haarlem"))); } public static void fill(Map<City,Country> m) { /* as before */ /* BUT : m.put(new City(“AAAAA”),new City(“BBBBB”) */ /* IS NOT POSSIBLE !!! */ } } 56 Defining generics public interface Iterable<T> { public Iterator<T> iterator(); } public interface Collection<E> extends Iterable<E> { public boolean add(E o); <S> S[] toArray(S[]) a; // parameterized method // ... many more methods } when type is invoked with parameter T : - as if <T> is substituted by invocation parameter - BUT : no source generation mechanism (as in C++ templates) - static check at compile time - addition of necessary bytecodes to convert to necessary types by compiler 57 Wildcards The tricky bit (counter-intuitive) Given type B subtype of type A THEN Collection<B> is NOT a subtype of Collection<A> Why ? To ensure static type safety !!! e.g. List<String> lstring=new ArrayList<String>(); List<Object> lobject=new ArrayList<Object>(); lstring.add(“Hello there”); // OK : “Hello there” is String lobject=lstring; // suppose this were allowed lobject.add(new Integer(10)); // OK : Integer is an Object String s0=lstring.get(0); // OK String s1=lstring.get(1); // attempt to store Integer in String ! 58 Wildcards class A { public void f() {System.out.println("a.f()");} } class B extends A { public void g() {System.out.println("b.g()");} } public class Main { public static void main(String[] args) { List<B> lb=new ArrayList<B>(); List<A> la=new ArrayList<A>(); lb.add(new B()); la=lb; // IF this were allowed la.add(new A()); lb.get(0).g(); lb.get(1).g(); // THEN this would generate // run-time exception !!! } } 59 Wildcards Super class of Collection<A> ??? Collection<?> ? : wildcard pronounced as “unknown” (not “anything”) BUT : nothing can be added to Collection of unknown ! otherwise : same problem as before ! List<B> lb=new ArrayList<B>(); List<?> la; lb.add(new B()); la=lb; // OK now ! la.add(new A()); // suppose this were OK lb.get(0).g(); lb.get(1).g(); // again problematic 60 Unbounded wildcards : example public static void main(String[] args) { List<B> lb=new ArrayList<B>(); List<?> la; lb.add(new B()); lb.add(new B()); la=lb; print(lb); print(la); } public static void print(List<?> l) { int n=1; for(Object o : l) { System.out.println(n+" : "+o); n++; } } } limited usage ! - <?> only to be resolved to Object (otherwise : unsafe again ...) - only Object interface can be used ! - solution : bounded wildcards 61 Bounded wildcards public static void invokeF(List<?> l) { int n=1; for(Object o:l) {System.out.print("-> "+n+" :");o.f();n++;} } NOT allowed (requires unsafe downcast ((A)o).f() ) public static void invokeF(List<A> l) { int n=1; for(A o:l) {System.out.print("-> "+n+" :");o.f();n++;} } allowed BUT does not work when attempting to pass List<B> !!! public static void invokeF(List<? extends A> l) { int n=1; for(A o:l) {System.out.print("-> "+n+" :");o.f();n++;} } OK !!! Bounded wildcard 62 Bounded wildcards BUT : NOT allowed to add to wildcard variable ! WHY ? class A {public void f() {System.out.println("a.f()");}} class B extends A {public void g() {System.out.println("b.g()");}} class C extends A {public void h() {System.out.println("c.h()");}} public static void addSomething(List<? extends A> l) { l.add(new B()); // suppose this were allowed } public static void main(String[] args) { List<B> lb=new ArrayList<B>(); List<C> lc=new ArrayList<C>(); lb.add(new B()); lb.add(new B()); addSomething(lb); lc.add(new C()); addSomething(lc); (lc.get(1)).h(); // this would cause a runtime exception } 63 Arrays NOT Allowed : Arrays of parameterized component types e.g. List<String>[] o = new List<String>[5]; Exception : unbound parameterized types allowed e.g. List<?>[] o = new List<?>[5]; 64 Parameterized methods Syntax modifiers <type parameters> return_type method name(formal param list) - return type and formal parameter list can depend on <type parameters> ! - type parameters are inferred by the compiler when method is invoked ! public static void main(String[] args) { List<B> lb=new ArrayList<B>(); List<A> la=new ArrayList<A>(); lb.add(new B());lb.add(new B()); la.add(new A());la.add(new A());la.add(new B()); invokeF(la); // T inferred to be A invokeF(lb); // T inferred to be B } public static <T extends A> void invokeF(List<T> l) { int n=1; for(A o:l) { System.out.print("-> "+n+" :");o.f();n++; } advice : use wildcards when possible } - no type interdependencies - type parameter only used once -> -> -> -> -> 1 2 3 1 2 :a.f() :a.f() :b.f() :b.f() :b.f() 65 Type erasure ? extends E ? super E ? extends E1 & E2 : an unknown subtype of E : an unknown supertype of E : an unknown subtype of E1 and E2 Type erasure effect (not exactly how it is implementd ... ) - generics converted to non generic version - all type parameters replaced by first mentioned upper bound - appropriate cast inserted where needed public String f(String s,List<String> l) { l.add(s); return l.get(0); } erasure public String f(String s,List l) { l.add(s); return (String)(l.get(0)); } 66 Parameterized methods example public static <T extends A> T getFirst(List<T> l) { return l.get(0); } convenience methods in Collections class public static <T> void copy(List<? super T> dest, List<? extends T> src) public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) 67