14/04/15
1
Generics in Java
Programming Projects
14/04/15 1
#Students per correct answers
0"
1"
2"
3"
4"
5"
6"
7"
8"
9"
10"
10" 9" 8" 7" 6" 5" 4" 3" 2" 1" 0"#"Correct"Answers"
Quiz"2"
10"
9"
8"
7"
6"
5"
4"
3"
2"
1"
0"
14/04/15
2
The collections’ interfaces
14/04/15 3
Con
tain
s uni
que
elem
ents
Ordered collection of elements
Ordered collection of elements with
head and tail; elements are always removed from the
head
Maps unique keys to values
Maps unique keys to values and sort
values Ordered unique
elements
Collections in Java • Array
– has a special language support
• Iterators
– Iterator(I)
• Collections also called containers
– Collection(I)
– Set(I)
• HashSet(c), TreeSet(c)
– List(I)
• ArrayList(c), LinkedList(c)
– Map(I)
• HashMap(c), TreeMap(c)
14/04/15 Barbara Russo
14/04/15
3
Built-in Java collections
• Collection interfaces and collection classes – Collection classes either full implements the collections
interfaces or are abstract classes providing skeleton implementations
– Examples: AbstractCollection, AbstractList, AbstractSequentialList, AbstractSet, AbstractMap
14/04/15 Barbara Russo
Getting from a collection • Let us consider this example:
List myIntegerList = new LinkedList();
myIntegerList.add(new Integer(0));
Integer x = (Integer) myIntegerList.iterator().next();
• The cast on line 3 is slightly annoying
• Typically, programmer knows what kind of data has been placed into a particular list. However, the cast is essential
• The compiler can only guarantee that iterator returns an object of type Object
14/04/15 6
14/04/15
4
Getting from a collection
• The casting introduces a run time error, since the programmer might be mistaken
• What if programmers could mark a list as being of a particular data type?
• This is the idea behind generics
14/04/15 7
Generics
• Generics allow you to abstract over types
• The most common examples are container (e.g., arrays and lists) types, such as those in the Collection hierarchy
• List<Integer> is a generic type that says that the list is of integers.
List<Integer> aList = new List<Integer>();
14/04/15 8
14/04/15
5
Example
• casting
List myIntegerList = new LinkedList();
myIntegerList.add(new Integer(0));
Integer x = (Integer) myIntegerList.iterator().next();
• with generics
List<Integer> myIntegerList = new LinkedList<Integer>();
myIntegerList.add(new Integer(0));
Integer x = myIntegerList.iterator().next();
14/04/15 9
run time
compile time
A big difference increases robustness
• With generics, the compiler can check the type correctness of the program at compile-time
• When we say that myIntegerList is declared with type List<Integer>, this tells us something about the variable myIntegerList and the compiler guarantees the type
• In contrast, the cast tells us something the programmer thinks is true at a single point in the code and it will be checked at run time:
14/04/15 10
14/04/15
6
Generics and derivation List<String> ls = new ArrayList<String>(); //Ok
List<Object> lo = ls; // pointing to the object referenced by ls. Compiler error!!!! Why?
• The trickier part of the question is line 2. – is a List of String a List of Object?
– Most people’s instinct is to answer: “sure!” lo.add(new Object()); // adding a new entry object of type Object is possible as lo is
//a reference variable of a List of Object types
String s = ls.get(0); // attempts to assign an Object to a String! NO!
– The object referenced by ls does not hold just strings anymore! We need to have another instrument more flexible, the Wildcards
14/04/15 11
Wildcards
• as List<Integer> is not a subtype of List<Object> we cannot use some useful practices of the classic Java anymore
• For example List can have any type of members whereas List<Integer> can only have Integer members
• Wildcards are used to get back classic behaviours for subtyping
14/04/15 12
14/04/15
7
Example: Collection of unknown • Collection<?> …The type of collection is unknown Collection<?> aCollection = new ArrayList<String>();
• aCollection is a reference of a Collection of unknown type and points to an object of type ArrayList of String – Note that Collection is an interface and ArrayList
Implements List which extends Collection
14/04/15 13
Limitation – adding
• With the collection of unknown, we cannot directly add to Collection a specific object:
aCollection.add(0,new Object()); //rises a compiler error
• as we do not know of what type is the collection and we can only pass elements that are subtypes of the unknown, – since we do not know the unknown type -> we can only
pass “null”, which is subtype of any type 14/04/15 14
14/04/15
8
Gaining - getting
• There is no compile time error to use get() and make use of the result, instead.
• We get back an unknown type, but we always know that it will be an object. – Thus we can assign the result of get() to a variable of type
Object (covariant property the return type can be a subclass of Object)
14/04/15 15
With collection of unknown…
“Populating a list is uncertain getting from a list is certain”
14/04/15 16
14/04/15
9
Bounded Wildcards
List<? extends Shape>
• It is a wildcard bounded by Shape – This allows to use the Wildcards with all the subtypes of
Shape
• As subtyping for generics is not allowed, bounded Wildcards allow to extend behaviours to children
14/04/15 17
Example public abstract class Shape{ public abstract void draw(Canvas c); } public class Circle extends Shape{ … public abstract void draw(Canvas c){…}; } public class Rectangle extends Shape{ … public abstract void draw(Canvas c){…}; } public class Canvas{ public void draw(Shape s){ s.draw(this); } public void drawAll(List<Shape> aList){ for(…){ aList.draw(this) } }
• drawAll can be only used with Shape and it cannot be used with any derived class!
• Then we define public void drawAllReally(List<? estends Shape> aList){
for(…){
aList.draw(this)
}
}
• Now we can use lists of any derived type of Shape
List<Circle> aListCircle= new List<Circle>();
Canvas.drawAllReally(aListCircle);
14/04/15 18
14/04/15
10
Careful! • Again, it is illegal to write directly into a list through the body
of a method public void addRectangle(List<? extends Shape> aList){
aList.add(0,new Rectangle()); //compile time error
}
• As we do not know the subtypes of Shape and whether the subtype of Shape is a Rectangle (or a parent class of Rectangle) i.e.: – Rectangle extends Base and Base extends Shape
– We need a new instrument: parametrized types and methods…
14/04/15 19
Parameterized type • A parameterized type is a class
public class Map<E> {…} ;
– Where E is a parameter (it is known but not defined)
• In the use of the class, all occurrences of the formal type parameter (E) are replaced by the actual type argument (e.g., Integer).
Map<Integer> aMap = new aMap<Integer>();
• Map<Integer> stands for a version of Map where E has been uniformly replaced by Integer
14/04/15 20
14/04/15
11
Note: Pseudo polymorphism with Marker Interfaces
• Parametrisation of a class can be done through the use of empty interfaces called Marker.
• Makers allow to group classes that want to have the same services. They are empty.
• Ex: all the classes that implement Cloneable (I) can use (and must override) the clone() method of Object
• Maker interfaces are not really providing a parameter …
Parametrized types … public interface Map<K, V> {
public void put(K key, V value);
public V get(K key);
}
...
Map<String, String> m = new HashMap<String, String>();
• where HashMap<String,String> defines an implementation of Map<String,String>
14/04/15 22
a parameterised type can have more than one parameter
14/04/15
12
…and methods
• one or more parameters are inserted after the modifier parameters in method declaration
public <T> void add(T t, List<T> aList){
aList.add(t); //correct
}
14/04/15 23
…and methods
public <T> void add(T t, List<T> aList){aList.add(t); //finally we can fill a list}
• or
public <T> void add(List<T> aList, List<? Extends T> aChildList){…};
• or
public <T,S extends T> void add(List<T> aList, List<S> aSmallList){…}; // equivalent to the one above if S extends T
• or
public <T> void add(List<T> aList, List<S extends T> aSmallLsit){…}; // equivalent to the one above
• or
public <T> List<T> returnNewList(List<T> aList){…}; 14/04/15 24
Finally we can fill a list!
14/04/15
13
Parameterised types with interfaces • With pseudo polymorphism; Comparable
is an interface java.lang
class MySortedList{
private Comparable [] elements;
…
public SortedList (){
elements = new Comparable[size];
}
public int add(Comparable t);
public Comparable remove(int index);
public int size();
}
• With generics
class MySortedList<T implements Comparable>{
private T [] elements;
…
public SortedList (){
elements = new T[size];
}
public int add(T t);
public T remove(int index);
public int size();
}
14/04/15 25
Parameterised types with interfaces With pseudo polymorphism;
public static void main(String [] args){
MySortedList list = new MySortedList();
// adding Integers
…
Integer i = (Integer)list.remove(0);
}
As I do not know what will be the implementation type of the object at 0, I have to cast in any case.
With generics
public static void main(String [] args){
class MySortedList<Integer> list = new
MySortedList<Integer>();
// adding Integers
…
Integer i = list.remove(0);
}
Here I only know that T implements Comparable. Integer is a standard implementation of Comparable
14/04/15 26 http://docs.oracle.com/javase/1.3/docs/api/java/lang/Comparable.html
14/04/15
14
Inference of types
• What does it happen when types in parametrised methods are different?
• The compiler infers types – It always infer the most generic
14/04/15 27
Compiler’s inference - Example Static <T> fromArrayToCollection(T[] a, Collection<T> c){
for(T o : a){
c.add(o);
}
}
Object[] aCO = new Object[100];
Collection<Object> aCollectionObject = new ArrayList<Object>();
String[] aCS = new String[100];
Collection<String> aCollectionString = new ArrayList<String>();
Integer[] aCI = new Integer[100];
Float[] aCF = new Float[100];
Number[] aCN = new Number[100];
Collection<Number> aCollectionNumber = new ArrayList<Number>();
fromArrayToCollection(aCO,aCollectionObject);
//T is inferred to be Object
fromArrayToCollection(aCS,aCollectionString);
// T is inferred to be String
fromArrayToCollection(aCS,aCollectionObject);
// T is inferred to be Object
fromArrayToCollection(aCI,aCollectionNumber);
// T is inferred to be Number
fromArrayToCollection(aCF,aCollectionNumber);
// T is inferred to be Number
fromArrayToCollection(aCN,aCollectionNumber);
// T is inferred to be Number
fromArrayToCollection(aCN,aCollectionString);
// T compile time error
The compiler infers from the less specialized type
from: http://download.oracle.com/javase/tutorial/extra/generics/methods.html
14/04/15
15
Raw type
• A raw type is the classic type
• For example – Collection is a classic type
– Collection<V> is the corresponding generic with type V. The raw type of Collection<V> is Collection
14/04/15 29
Type erasure • Type Erasure is the phase after Inference of types in which the compiler translates
the source into bytecode.
• Type erasure exists to have compliance with non generics code (legacy code)
• Consider the example of the parameterized List
public interface List<E> {
void add(E x);
Iterator<E> iterator();
}
public interface Iterator<E> {
E next();
boolean hasNext();
}
14/04/15 30
14/04/15
16
Type erasure
• at erasure the generic type are removed – List<Number> becomes List which can contain any type of
object
• The compiler just check the correctness of the types and then save bytecode as in traditional Java compiled code
• At run time is impossible to deduce the original type
14/04/15 31
Type erasure • If a generic type is not parametric like List<Integer> its erasure is the raw type (List)
• If the generic type is unbounded (like List<E> or List<?>) its erasure will be Object
• If the generic type is bounded its erasure will be the base (or the implementation of it if the bound is an interface)
<K extends V> -> erasure=V or W (implements V) if V interface
• If the generic type is bounded by a generic then its erasure will be the raw type of the base.
<K extends Comparable<V>>
-> erasure= implementation of Comparable (as Comparable is an interface)
14/04/15 32
14/04/15
17
14/04/15 33
Original Code
Compiler’s Translation
Two ways to handle parameterized types • Specialization of objects
– each instance of the parameterized type creates a new representation. List<Integer> and List<Float> are two different representations of List<T>
• Sharing of objects
– the code for List<T> is generated by the compiler for one representation and all the instances created refer to this representation
• Java uses the second approach
– Some problems with simple types: a generic with simple type is not allowed as they are treated differently by the compiler
14/04/15 34
14/04/15
18
“is instance of” a parametric type
• …As implication, it makes no sense to ask an instance if it is an instance of a particular invocation of a generic type:
Collection<String> cs = new ArrayList<String>();
• if (cs instanceof Collection<String>) { ...} // illegal
• As Collection<String> is compiled into one single representation, the implementation of Collection
14/04/15 35
Getting an instance of a parametric type
• and it is also illegal to write (code will not compile)
new T();
• where T is a parametric type as we do not know the true type of the object and as such we cannot call its constructor
14/04/15 36
14/04/15
19
Getting an instance of a parametric type
• To get an instance of a parametric type we use the genericization of Class,
Class<T>{
T newInstance(); // in Class we had “Object newInstance();”
}
• and define a method that gets the instance of T through newInstance(), getClass()
public final Class<? extends T> getClass() {}
14/04/15 37
Getting an instance of a parametric type
• Another implication of the fact that a generic class is shared among all its instances
List <String> l1 = new ArrayList<String>();
List<Integer> l2 = new ArrayList<Integer>();
System.out.println(l1.getClass() == l2.getClass());
• It prints true, because all instances of a generic class have the same raw type, regardless of their actual type parameters
14/04/15 38
14/04/15
20
Static generic type class and method
• A static member cannot be implemented as generics
• This is because it is shared by all the objects and the objects of a generic type are of unknown type
14/04/15 39
A difference with Template in C++
• Generics do not generate a new class for each specialization of the formal parameter
• A generic type declaration is compiled once for all and turned into a single class file like ordinary class files. There are no multiple copies of the generics in any place
• In C++ for Templates this is not true
14/04/15 40
14/04/15
21
Example interface MinMax<T extends Comparable<T>> { T min(); T max(); } class MyClass<T extends Comparable<T>> implements MinMax<T > { T[] vals; MyClass(T[] o) { vals = o; } public T min() { T v = vals[0]; for(int i=1; i < vals.length; i++) if(vals[i].compareTo(v) < 0) v = vals[i]; return v; } public T max() { T v = vals[0]; for(int i=1; i < vals.length; i++) if(vals[i].compareTo(v) > 0) v = vals[i]; return v; } }
public class GenIFDemo {
public static void main(String args[]) {
Integer inums[] = {3, 6, 2, 8, 6 };
Character chs[] = {'b', 'r', 'p', 'w' };
MyClass<Integer> iob = new MyClass<Integer>(inums);
MyClass<Character> cob = new MyClass<Character>(chs); System.out.println("Max value in inums: " + iob.max()); System.out.println("Min value in inums: " + iob.min()); System.out.println("Max value in chs: " + cob.max()); System.out.println("Min value in chs: " + cob.min()); } }
14/04/15 41
Source code
14/04/15 42
[1] package card; [2] import game.MyCard; [3] public interface Play { [4] int STOP = -1; [5] int OK = 1; [6] } [7] package card; [8] public abstract class Card implements Play{ [9] protected static int number = 0; [10] public int points; [11] public String color; [12] public Card(int i, String c){ [13] points = i; [14] color = c; [15] } [16]}
14/04/15
22
Source code cont.
14/04/15 43
[17] package game; [18] import card.*; [19] public class MyCard extends card.Card{ [20] private String name; [21] private int next; [22] private int num = 0; [23] public MyCard(int p, String c){ [24] super(p, c); [25] number++; [26] } [27] } [28] package game; [29] import card.Card; [30] public class Game { [31] private int players; [32] private int drinks; [33] private MyCard mycard; [34] public Game(int z, int y){ [35] this.players = y; [36] this.drinks = z; [37] mycard = new MyCard(10, "red"); [38] }
Source code cont.
14/04/15 44
[39] public static void main(String[] args) { [40] int counter = 2; [41] Game[] mygames = new Game[counter]; [42] for (int u=0; u<counter; u++){ [43] mygames[u] = new Game(u*u, 4); [44] } [45] }
14/04/15
23
Draw the stack diagram • Draw the stack diagram for when the
execution reaches: 1. The end of line [38] for the first time 2. The end of line [38] for the second time
14/04/15 45
Solution 1
14/04/15 46
SAR(for)
Heap
50000
Class card.Card
number 0
SL @300
SP RA RV
@100
N/E
counter 2 SL
@80
AR(main)
300
@100
AR(ctor)
370
interface @3500 350
SP RA
@350 @72
this @15000
SL @100
RV N/E
Stack
mygames @??
10000
Object of class Array mygames[0] ??
15000
Object of class game.Game
mycard ??
drinks 0
35000
Interface card.Play
STOP -1
players
17000
Object of class game.MyCard
4
mygames[1] ??
u 0
z 0
y 4
OK 1
this @50000
num 0 next ??
name ??
color ??
points ??
AR(ctor) 390
AR(ctor) 400
@10000
- 10
red
- 1
@15000
@17000
14/04/15
24
Solution 2
14/04/15 47
SAR(for)
Heap
50000
Class card.Card
number 1
SL @300
SP RA RV
@100
N/E
counter 2 SL
@80
AR(main)
300
@100
AR(ctor)
370
interface @3500 350
SP RA
@350 @72
this @19000
SL @100
RV N/E
Stack
mygames @10000
10000
Object of class Array mygames[0] @15000
15000
Object of class game.Game
mycard @1700
drinks 0
35000
Interface card.Play
STOP -1
players
17000
Object of class game.MyCard
4
mygames[1] ??
u 1
z 1
y 4
OK 1
class @5000
num 0 next ??
name ??
color red
points 10
AR(ctor) 390
19000
Object of class game.Game
mycard ??
drinks 1 players
21000
Object of class game.MyCard
4
class @5000
num 0 next ??
name ??
color ??
points ??
AR(ctor) 400
- 10 red
- 2
@19000
@21000
Top Related