Download Collections

Document related concepts
no text concepts found
Transcript
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