Generics in Java Programming Projects 14/04/15 1 #Students per correct answers Quiz"2" 10" 9" 8" 7" 6" 5" 4" 3" 2" 1" 0" 10" 9" 8" 7" 6" 5" 4" 3" 2" 1" 0" #"Correct"Answers" 10" 9" 8" 7" 6" 5" 4" 3" 2" 1" 0" 1
The collections interfaces Maps unique keys to values Contains unique elements Ordered collection Ordered collection Ordered unique of elements of elements with elements head and tail; 14/04/15 elements are always 3 removed from the head Maps unique keys to values and sort values 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 2
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 3
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 4
Example casting run time with generics compile time List myintegerlist = new LinkedList(); myintegerlist.add(new Integer(0)); Integer x = (Integer) myintegerlist.iterator().next(); List<Integer> myintegerlist = new LinkedList<Integer>(); myintegerlist.add(new Integer(0)); Integer x = myintegerlist.iterator().next(); 14/04/15 9 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 5
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 6
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 7
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 8
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 9
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 10
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); a parameterised type can have more than one parameter... Map<String, String> m = new HashMap<String, String>(); where HashMap<String,String> defines an implementation of Map<String,String> 14/04/15 22 11
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 Finally we can fill a list! 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 12
Parameterised types with interfaces With pseudo polymorphism; Comparable is an interface java.lang With generics class MySortedList{ private Comparable [] elements; public SortedList (){ elements = new Comparable[size]; public int add(comparable t); public Comparable remove(int index); public int size(); 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); With generics public static void main(string [] args){ class MySortedList<Integer> list = new MySortedList<Integer>(); // adding Integers Integer i = 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. 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 13
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>(); 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 String[] acs = new String[100]; Collection<String> acollectionstring = new ArrayList<String>(); fromarraytocollection(acf,acollectionnumber); // T is inferred to be Number fromarraytocollection(acn,acollectionnumber); Integer[] aci = new Integer[100]; Float[] acf = new Float[100]; Number[] acn = new Number[100]; // T is inferred to be Number fromarraytocollection(acn,acollectionstring); // T compile time error Collection<Number> acollectionnumber = new ArrayList<Number>(); from: http://download.oracle.com/javase/tutorial/extra/generics/methods.html The compiler infers from the less specialized type 14
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 15
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 16
Original Code Compiler s Translation 14/04/15 33 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 17
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 18
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 19
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 20
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 [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 42 21
[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; Source code cont. 14/04/15 43 [37] mycard = new MyCard(10, "red"); [38] Source code cont. [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 44 22
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 400 390 AR(ctor) 370 AR(ctor) AR(ctor) 4 y 0 z @100 SL @350 SP @72 RA N/E RV @15000 this Object of class game.mycard?? - 10 points?? red color?? name?? next 0 num 17000 @50000 this Object of class game.game 4 players 0 drinks 15000 @17000?? mycard Object of class Array @15000?? mygames[0]?? mygames[1] SAR(for) 0 u 10000 @300 SL Class card.card 350 @3500 interface @10000 @?? mygames 0-1 number counter 50000 2 AR(main) @100 SL Interface card.play @100 SP -1 STOP @80 RA 14/04/15 300 N/E RV 35000 1 OK 46 Stack Heap 23
Solution Stack 2 400 AR(ctor) 17000 390 AR(ctor) Object of class game.game 4 players 4 y 0 drinks AR(ctor) 1 z 15000 @1700 mycard @100 SL @350 SP Object of class Array @72 RA @15000 mygames[0] Object of class game.mycard N/E RV @19000?? mygames[1]?? - 10 points 370 @19000 this?? red color 10000 SAR(for) 1 u?? name Class card.card @300 SL?? next @3500 interface 350 0 num 1-2 number 21000 @5000 class @10000 mygames 50000 2 counter Object of class game.game AR(main) Interface card.play players @100 SL 4-1 STOP @100 SP 1 drinks 14/04/15 @80 RA 35000 1 OK @21000?? mycard 47 300 N/E RV 19000 Heap Object of class game.mycard 10 red???? 0 @5000 points color name next num class 24