generics in java - inf.unibz.itrusso/ap/generics_twoslides.pdf · • with generics, the compiler...

24
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

Upload: others

Post on 16-Jun-2020

7 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Generics in Java - inf.unibz.itrusso/AP/Generics_TwoSlides.pdf · • With generics, the compiler can check the type correctness of the program at compile-time • When we say that

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"

Page 2: Generics in Java - inf.unibz.itrusso/AP/Generics_TwoSlides.pdf · • With generics, the compiler can check the type correctness of the program at compile-time • When we say that

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

Page 3: Generics in Java - inf.unibz.itrusso/AP/Generics_TwoSlides.pdf · • With generics, the compiler can check the type correctness of the program at compile-time • When we say that

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

Page 4: Generics in Java - inf.unibz.itrusso/AP/Generics_TwoSlides.pdf · • With generics, the compiler can check the type correctness of the program at compile-time • When we say that

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

Page 5: Generics in Java - inf.unibz.itrusso/AP/Generics_TwoSlides.pdf · • With generics, the compiler can check the type correctness of the program at compile-time • When we say that

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

Page 6: Generics in Java - inf.unibz.itrusso/AP/Generics_TwoSlides.pdf · • With generics, the compiler can check the type correctness of the program at compile-time • When we say that

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

Page 7: Generics in Java - inf.unibz.itrusso/AP/Generics_TwoSlides.pdf · • With generics, the compiler can check the type correctness of the program at compile-time • When we say that

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

Page 8: Generics in Java - inf.unibz.itrusso/AP/Generics_TwoSlides.pdf · • With generics, the compiler can check the type correctness of the program at compile-time • When we say that

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

Page 9: Generics in Java - inf.unibz.itrusso/AP/Generics_TwoSlides.pdf · • With generics, the compiler can check the type correctness of the program at compile-time • When we say that

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

Page 10: Generics in Java - inf.unibz.itrusso/AP/Generics_TwoSlides.pdf · • With generics, the compiler can check the type correctness of the program at compile-time • When we say that

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

Page 11: Generics in Java - inf.unibz.itrusso/AP/Generics_TwoSlides.pdf · • With generics, the compiler can check the type correctness of the program at compile-time • When we say that

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

Page 12: Generics in Java - inf.unibz.itrusso/AP/Generics_TwoSlides.pdf · • With generics, the compiler can check the type correctness of the program at compile-time • When we say that

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!

Page 13: Generics in Java - inf.unibz.itrusso/AP/Generics_TwoSlides.pdf · • With generics, the compiler can check the type correctness of the program at compile-time • When we say that

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

Page 14: Generics in Java - inf.unibz.itrusso/AP/Generics_TwoSlides.pdf · • With generics, the compiler can check the type correctness of the program at compile-time • When we say that

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

Page 15: Generics in Java - inf.unibz.itrusso/AP/Generics_TwoSlides.pdf · • With generics, the compiler can check the type correctness of the program at compile-time • When we say that

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

Page 16: Generics in Java - inf.unibz.itrusso/AP/Generics_TwoSlides.pdf · • With generics, the compiler can check the type correctness of the program at compile-time • When we say that

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

Page 17: Generics in Java - inf.unibz.itrusso/AP/Generics_TwoSlides.pdf · • With generics, the compiler can check the type correctness of the program at compile-time • When we say that

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

Page 18: Generics in Java - inf.unibz.itrusso/AP/Generics_TwoSlides.pdf · • With generics, the compiler can check the type correctness of the program at compile-time • When we say that

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

Page 19: Generics in Java - inf.unibz.itrusso/AP/Generics_TwoSlides.pdf · • With generics, the compiler can check the type correctness of the program at compile-time • When we say that

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

Page 20: Generics in Java - inf.unibz.itrusso/AP/Generics_TwoSlides.pdf · • With generics, the compiler can check the type correctness of the program at compile-time • When we say that

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

Page 21: Generics in Java - inf.unibz.itrusso/AP/Generics_TwoSlides.pdf · • With generics, the compiler can check the type correctness of the program at compile-time • When we say that

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]}

Page 22: Generics in Java - inf.unibz.itrusso/AP/Generics_TwoSlides.pdf · • With generics, the compiler can check the type correctness of the program at compile-time • When we say that

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] }

Page 23: Generics in Java - inf.unibz.itrusso/AP/Generics_TwoSlides.pdf · • With generics, the compiler can check the type correctness of the program at compile-time • When we say that

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

Page 24: Generics in Java - inf.unibz.itrusso/AP/Generics_TwoSlides.pdf · • With generics, the compiler can check the type correctness of the program at compile-time • When we say that

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