13. Java generics

annuncio pubblicitario
AA2016-2017
13.Javagenerics
1
JavaInterfaceeastrazione
interface ListOfNumbers {
boolean add(Number elt);
Number get(int index);
}
interface ListOfIntegers {
boolean add(Integer elt);
Integer get(int index);
}
…eListOfStringse…
UsiamoI,pi!!!
List<Integer>
//Necessarioastrarresui,pi
List<Number>
interface List<E> {
List<String>
boolean add(E n);
E get(int index);
List<List<String>>
}
…
2
ParametrieparametridiApo
interface ListOfIntegers {
boolean add(Integer elt); •  Dichiarazionedelparametro
Integer get(int index);
formale
}
•  Istanziatoconunaespressione
chehailAporichiesto(lst.add(7))
•  Tipodiadd:
Integer→boolean
interface List<E> {
boolean add(E elt);
•  DichiarazionediunparametrodiApo
E get(int index);
•  IstanziabileconunqualunqueApo
}
•  List<String>
3
VariabilidiApo
Dichiarazione
class NewSet<T> implements Set<T> {
// rep invariant:
//
non-null, contains no duplicates
// ...
List<T> theRep;
T lastItemInserted;
...
}
Use
UAlizzo
4
Dichiarareclassigeneriche
class Name<TypeVar1, …, TypeVarN> {…}
interface Name<TypeVar1, …, TypeVarN> {…}
o  convenzionistandard
TperType,EperElement,
KperKey,VperValue,…
IstanziareunaclassegenericasignificafornireunvalorediApo
Name<Type1, …, TypeN>
5
IstanziareApi
boolean add1(Object
boolean add2(Number
add1(new Date( ));
add2(new Date( ));
elt);
elt);
// OK
// compile-time error
Limitesuperiore
gerarchia
interface List1<E extends Object> {…}
interface List2<E extends Number> {…}
List1<Date> // OK, Date è un sottotipo di Object
List2<Date> // compile-time error, Date non è
// sottotipo di Number
6
VisioneeffeSvadeigenerici
class Name<TypeVar1 extends Type1,
…,
TypeVarN extends TypeN> {…}
o  (analogoperleinterfacce)
o  (intuizione:Objectèillimitesuperioredidefaultnellagerarchiadei
Api)
IstanziazioneidenAca
Name<Type1, …, TypeN>
  Macompile-,meerrorseilApononèunsoVoApodellimitesuperiore
dellagerarchia
7
UsiamolevariabilidiApo
SipossonoeffeVuaretuVeleoperazionicompaAbiliconillimitesuperiore
dellagerarchia
o  conceVualmentequestocorrispondeaforzareunaprecondizionesulla
istanziazionedelApo
class List1<E extends Object> {
void m(E arg) {
arg.asInt( ); // compiler error, E potrebbe
// non avere l’operazione asInt
}
}
class List2<E extends Number> {
void m(E arg) {
arg.asInt( ); // OK, Number e tutti i suoi
// sottotipi supportano asInt
}
}
8
VincolidiApo
<TypeVar extends SuperType>
o  upperbound;vabeneilsupertypeounodeisuoisoVoApi
<TypeVar extends ClassA & InterfB & InterfC & … >
o  Mul,pleupperbounds
<TypeVar super SubType>
o  lowerbound;vabeneilsoVoApoounoqualunquedeisuoisuperApi
Esempio
// strutture di ordine su alberi
public class TreeSet<T extends Comparable<T>> {
...
}
9
Esempio
class Utils {
static double sumList(List<Number> lst) {
double result = 0.0;
for (Number n : lst)
result += n.doubleValue( );
return result;
}
static Number choose(List<Number> lst) {
int i = ... // numero random < lst.size
return lst.get(i);
}
}
10
Soluzioneefficace
class Utils {
Dichiarare
static <T extends Number>
double sumList(List<T> lst) {
ivincolisuiApi
double result = 0.0;
for (Number n : lst) // T also works
result += n.doubleValue();
return result;
}
Dichiarare
}
static <T>
ivincolisuiApi
T choose(List<T> lst) {
int i = … // random number < lst.size
return lst.get(i);
}
11
Metodigenerici
MetodichepossonousareiApigenericidelleclassi
PossonodichiarareancheiloroApigenerici
  Leinvocazionidimetodigenericidevono
obbligatoriamenteistanziareiparametridiApo
o  staAcamente:unaformadiinferenzadiApo
12
Unesempio
public class InsertionSort<T extends Comparable<T>> {
public void sort(T[ ] x) {
T tmp;
for (int i = 1; i < x.length; i++) {
// invariant: x[0],...,x[i-1] sorted
tmp = x[i];
for (int j = i;
j > 0 && x[j-1].compareTo(tmp) > 0; j--)
x[j] = x[j-1];
x[j] = tmp;
}
}
}
13
GenericielanozionedisoVoApo
Number
List<Number>
Integer
?
List<Integer>
  IntegerèunsoVoApodiNumber
  List<Integer>èunsoVoApodiList<Number>?
14
QualisonoleregolediJava?
SeType2eType3sonodifferenA,eType2èun
soVoApodiType3,alloraType1<Type2>nonèun
soVoApodiType1<Type3>
Formalmente:lanozionedisoVoApousatainJavaè
invarianteperleclassigeneriche
15
Esempi(daJava)
  TipiesoVoApi
o 
o 
o 
IntegerèunsoVoApodiNumber
ArrayList<E>èunsoVoApodiList<E>
List<E>èunsoVoApodiCollecAon<E>
  Ma
o 
List<Integer>nonèunsoVoApodiList<Number>
16
List<Number>eList<Integer>
interface List<T> {
boolean add(T elt);
T get(int index);
}
Number
Integer
typeList<Number>has
boolean add(Number elt);
Number get(int index);
typeList<Integer>has
boolean add(Integer elt);
Integer get(int index);
List<Number>nonèunsuperApodiList<Integer>
17
Unadiscussione
(percapireanchelaricercanelseVore)
interface List<T> {
T get(int index);
}
Number
Integer
typeList<Number>has
Number get(int index);
typeList<Integer>has
Integer get(int index);
LanozionedisoVoApocovariantesarebbecorreVa
o  List<Integer>soVoApodiList<Number>
SfortunatamenteJavanonadoVaquestasoluzione
18
Alloraparliamoanchedicontravarianza
interface List<T> {
boolean add(T elt);
}
Number
Integer
typeList<Number>has
boolean add(Number elt);
typeList<Integer>has
boolean add(Integer elt);
LanozionedisoVoApocontravariantesarebbealtreVantocorreVa
o  List<Number>èsoVoApodiList<Integer>
MaJava...
19
AltriaspeS
  List<Integer>eList<Number>nonsonocorrelaAdallanozione
disoVoApo
  TuVavia,indiversicasilanozionedisoVoAposuigenericifunzionacome
unoseloaspeVaancheinJava
  Esempio:assumiamocheLargeBagextendsBag,allora
o  LargeBag<Integer>èunsoVoApodiBag<Integer>
o  LargeBag<Number>èunsoVoApodiBag<Number>
o  LargeBag<String>èunsoVoApodiBag<String>
o  …
20
addAll
interface Set<E> {
// Aggiunge a this tutti gli elementi di c
// (che non appartengono a this)
void addAll(??? c);
}
QualeèilmigliorApoperilparametroformale?
o  Ilpiùampiopossibile…
o  …chepermeVediavereimplementazionicorreVe
21
addAll
interface Set<E> {
// Aggiunge a this tutti gli elementi di c
// (che non appartengono a this)
void addAll(??? c);
}
Unaprimasceltaèvoid addAll(Set<E> c);
TropporestriSvo
o  unparametroaVualediApoList<E>nonsarebbepermesso,eciòè
spiacevole…
22
addAll
interface Set<E> {
// Aggiunge a this tutti gli elementi di c
// (che non appartengono a this)
void addAll(??? c);
}
SecondotentaAvo: void addAll(Collection<E> c);
TropporestriSvo
o  ilparametroaVualediApoList<Integer>perSet<Number>
nonvabeneancheseaddAllhasolobisognodileggeredacenon
dimodificarlo!!!
o  questaèlaprincipalelimitazionedellanozionediinvarianzaperi
genericiinJava
23
addAll
interface Set<E> {
// Aggiunge a this tutti gli elementi di c
// (che non appartengono a this)
void addAll(??? c);
}
Proviamoancora
<T extends E> void addAll(Collection<T> c);
Ideabuona:unparametrogenericomavincolato
o  possoavereunparametroaVualediApoList<Integer>per
Set<Number>
o  addAllnonpuòvederenell’implementazioneilApoT,sasolocheè
unsoVoApodiE,enonpuòmodificarelacollecAonc
24
Altroesempio
<T> void copyTo(List<T> dst, List<T> src) {
for (T t : src)
dst.add(t);
}
Lasoluzionevabene,maancorameglio
<T1, T2 extends T1> void copyTo(List<T1> dst,
List<T2> src) {
for (T2 t : src)
dst.add(t);
}
25
Wildcard
Sintassidellewildcard
o  ? extends Type,soVoApononspecificatodelApoType
o  ?notazionesemplificataper? extends Object
o  ? super Type,superApononspecificatodelApoType
wildcard=unavariabilediApoanonima
o  ?Apononconosciuto
o  siusanolewildcardquandosiusaunApoesaVamenteunavoltama
nonsiconosceilnome
o  l’unicacosachesisaèl’unicitàdelApo
26
Esempi
interface Set<E> {
void addAll(Collection<? extends E> c);
}
o 
maggiormenteflessibilerispeVoa
void addAll(Collection<E> c);
o 
espressivacome
<T extends E> void addAll(Collection<T> c);
27
ProducerExtends,ConsumerSuper
Quandosiusanolewildcard?
o  siusa? extends TneicasiincuisivoglionooVeneredeivalori(da
unproduVoredivalori)
o  siusa? super Tneicasiincuisivoglionoinserirevalori(inun
consumatore)
o  nonvannousate(bastaT)quandosioVengonoesiproduconovalori
<T> void copy(List<? super T> dst,
List<? extends T> src);
28
?vsObject
?TipoparAcolareanonimo
void printAll(List<?> lst) {…}
QualeèladifferenzatraList<?>eList<Object>?
o possiamoistanziare?conunApoqualunque:Object,String,…
o  List<Object>èpiùrestriSvo:List<String>nonvabene
QualeèladifferenzatraList<Foo>eList<? extends Foo>
o nelsecondocasoilApoanonimoèunsoVoAposconosciutodiFoo
List<? extends Animal> puòmemorizzareGiraffema
nonZebre
29
Rawtypes
  Conrawtypesiindicaunaclasse/interfaccia
senzanessunargomentodiApo(legacycode)
Vector<Integer> intVec = new Vector<Integer>();
Vector rawVec = new Vector();
// OK
Vector<String> stringVec = new Vector<String>();
Vector rawVec = stringVec;
// OK
Vector rawVec = new Vector();
// rawVector is a raw type of Vector<T>
Vector<Integer> intVector = rawVector;
// warning: unchecked conversion
30
InferenzadiApo
  Inferenza:capacitàdicontrollareunainvocazionedimetodo
eladichiarazionedimetodoassociataalfinedideterminare
ilApopiùspecifico,inaccordoaivincolidiApopresenA,che
rendeilmetodoeffeSvamenteinvocabile
class MyClass<S> {
<T> MyClass(T t) { ... }
}
new MyClass<Integer>("")
diamondnotaAon
MyClass<Integer> myObject = new MyClass<>("")
31
Ancoral’inferenzadiApo
static <T> List<T> emptyList();
metodoinCollecAons
List<String> listOne = Collections.<String>emptyList();
List<String> listOne = Collections.emptyList();
void processStringList(List<String> stringList) { ... }
processStringList(Collections.<String>emptyList());
processStringList(Collections.emptyList());
Java8inferiscedalApodelparametro
obbligatorioInJava7
32
Javaarray
SappiamobenecomeoperarecongliarrayinJava…Vero?
Analizziamoquestaclasse
class Array<T> {
public T get(int i) { … "op" … }
public T set(T newVal, int i) { … "op" … }
}
Domanda:SeType1èunsoVoApodiType2,qualeèlarelazionetra
Type1[]eType2[]??
33
Sorpresa!
SappiamocheperigenericilanozionedisoVoApoèinvariante,pertanto
seType1èunsoVoApodiType2,alloraType1[]eType2[]non
dovrebberoesserecorrelaA
  MaJavaèstrano,seType1èunsoVoApodiType2,alloraType1[]è
unsoVoApodiType2[]
o  Java(maancheC#)hafaVoquestasceltaprimadell’introduzionedei
generici
o  cambiarlaoraèunpo’troppoinvasivoperipigriprogrammatoriJava
(commentoobbligatoperchifaricercasuiprincipideilinguaggidi
programmazione)
34
Cisonoanchecose“buone”
Gliinglesidicono:“Programmersdookaystuff”
LibraryHolding
Book
CD
void maybeSwap(LibraryHolding[ ] arr) {
if(arr[17].dueDate( ) < arr[34].dueDate( ))
// … swap arr[17] and arr[34]
}
// cliente
Book[ ] books = …;
maybeSwap(books); // usa la covarianza degli array
35
Mapuòandaremale
void replace17(LibraryHolding[ ] arr,
LibraryHolding h) {
arr[17] = h;
}
LibraryHolding
Book
CD
// il solito cliente
Book[] books = …;
LibraryHolding theWall = new CD("Pink Floyd",
"The Wall", … );
replace17(books, theWall);
Book b = books[17]; // contiene un CD
b.getChapters( );
// problema!!
36
LesceltediJava
  IlApodinamicoèunsoVoApodiquellostaAco
o  violatonelcasodiBook b
  LasceltadiJava
o  ogniarray“conosce”ilsuoApodinamico(Book[ ])
o  modificarea(run-Ame)conununsuperApodetermina
ArrayStoreException
  pertantoreplace17sollevaunaeccezione
o  EveryJavaarray-updateincludesrun-,mecheck
! (dallaspecificadellaJVM)
o  Morale:fateaVenzioneagliarrayinJava
37
Toogoodtobetrue:typeerasure
TuSiApigenericisonotrasformaAinObjectnelprocessodicompilazione
o  moAvo:backward-compaAbilityconilcodicevecchio
o  morale:arunAme,tuVeleistanziazionigenerichehannolostessoApo
List<String> lst1 = new ArrayList<String>( );
List<Integer> lst2 = new ArrayList<Integer>( );
lst1.getClass( ) == lst2.getClass( ) // true
38
GenericiecasAng
List<?> lg = new ArrayList<String>( );
List<String> ls = (List<String>) lg;
// ok
// warning
DalladocumentazioneJava:“Compilergivesanuncheckedwarning,
sincethisissomethingtherun-Amesystemwillnotcheckforyou”
Problema
public static <T> T badCast(T t, Object o){
return (T) o; // unchecked warning
}
39
equals
class Node<E> {
...
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Node<E>))
return false;
Erasure:Apo
dell’argomentonon
esistearunAme
Node<E> n = (Node<E>) obj;
return this.data( ).equals(n.data( ));
}
...
}
40
equals
class Node<E> {
...
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Node<?>))
return false;
Erasure:arunAme
nonsisacosasiaE
Node<E> n = (Node<E>) obj;
return this.data( ).equals(n.data( ));
}
...
}
41
Tips(dastackoverflow)
  StartbywriAngaconcreteinstanAaAon
o  getitcorrect(tesAng,reasoning,etc.)
o  considerwriAngasecondconcreteversion
  Generalizeitbyaddingtypeparameters
o  thinkaboutwhichtypesarethesameordifferent
o  thecompilerwillhelpyoufinderrors
42
JavaGenerics(JG)
  Ilcompilatoreverifical’uAlizzocorreVodeigenerici
  IparametridiAposonoeliminaAnelprocessodi
compilazioneeil“classfile”risultantedalla
compilazioneèunnormaleclassfilesenza
poliformismoparametrico
Esempio
class Vector<T> {
T[] v; int sz;
Vector() {
v = new T[15];
sz = 0;
}
<U implements Comparer<T>>
void sort(U c) {
…
c.compare(v[i], v[j]);
…
}
}
…
Vector<Button> v;
v.addElement(new Button());
Button b = v.elementAt(0);
class Vector {
Object[] v; int sz;
Vector() {
v = new Object[15];
sz = 0;
}
void sort(Comparer c) {
…
c.compare(v[i], v[j]);
…
}
}
…
Vector v;
v.addElement(new Button());
Button b =
(Button)b.elementAt(0);
Considerazioni
  JGaiutanoamigliorareilpolimorfismodella
soluzione
  Limiteprincipale:ilApoeffeSvoèpersoarunAmea
causadellatypeerasure
  TuVeleistanziazionisonoidenAficate
  EsistonoaltreimplementazionideigenericiperJava
GenericseJava
System
Feature
Parameterized
types
Polymorphic
methods
Type checking at
point of definition
Non-reference
instantiations
Exact run-time
types
Polymorphic virtual
methods
Type parameter
variance
JG/Pizza NextGen
PolyJ
Bracha,
Odersky,
Stoutamire,
Wadler
Bank, Liskov,
Myers
Cartwright,
Steele
Agesen,
Freund,
Mitchell
Generic CLR
Kennedy,
Syme
!
!
!
!
!
+ bounds
+ bounds
+ constraints
+ bounds
+ bounds
!
!
"
"
!
!
!
!
"
!
"
"
!
!
!
"
!
?
!
!
"
!
"
"
!
"
!
"
"
"
Unaan7cipazionedi
programmazioneavanzata
GenericC#
  KennedyandSymehaveextendedCLRtosupport
parametrictypes(thesameproposalhasbeenmade
forPolyJbyCartwrightandSteele)
  Theverifier,JITandloaderhavebeenchanged
  WhentheprogramneedsaninstanAaAonofa
generictypetheloadergeneratestheappropriate
type
  TheJITcanshareimplementaAonofreference
instanAaAons(Stack<String>hasessenAallythe
samecodeofStack<Object>)
GenericC#compiler
  GC#compilerimplementsaJGlikenotaAonfor
parametrictypes
  BoundsarethesameasinJG
  NOtype-inferenceongenericmethods:thetype
mustbespecifiedinthecall
  ExactrunAmetypesaregrantedbyCLRsovirtual
genericmethodsareallowed
  Alltypeconstructorscanbeparameterized:
struct,classes,interfacesanddelegates
Esempio
using System;
namespace n {
public class Foo<T> {
T[] v;
Foo() { v = new T[15]; }
public static
void Main(string[] args) {
Foo<string> f =
new Foo<string>();
f.v[0] = "Hello";
string h = f.v[0];
Console.Write(h);
}
}
}
.field private !0[] v
.method private hidebysig
specialname
rtspecialname
instance void .ctor() cil
managed {
.maxstack 2
ldarg.0
call
instance void
[mscorlib]System.Object::.c
tor()
ldarg.0
ldc.i4.s
15
newarr
!0
stfld
!0[] class n.Foo<!
0>::v
ret
} // end of method Foo::.ctor
Scarica