AA 2016-2017 13. Java generics - Dipartimento di...
Transcript of AA 2016-2017 13. Java generics - Dipartimento di...
13.JavagenericsAA2016-2017
1
JavaInterfaceeastrazione
interface ListOfNumbers { boolean add(Number elt); Number get(int index); } interface ListOfIntegers { boolean add(Integer elt); Integer get(int index); } …eListOfStringse…//Necessarioastrarresui,piinterface List<E> { boolean add(E n); E get(int index); }
2
UsiamoI,pi!!! List<Integer> List<Number> List<String> List<List<String>> …
ParametrieparametridiApo
interface ListOfIntegers { boolean add(Integer elt); Integer get(int index); } interface List<E> { boolean add(E elt); E get(int index); }
3
• Dichiarazionedelparametroformale
• IstanziatoconunaespressionechehailAporichiesto(lst.add(7))
• Tipodiadd:Integer→boolean
• DichiarazionediunparametrodiApo• IstanziabileconunqualunqueApo
• List<String>
VariabilidiApo
class NewSet<T> implements Set<T> { // rep invariant: // non-null, contains no duplicates // ... List<T> theRep; T lastItemInserted; ... }
4
Dichiarazione
UseUAlizzo
Dichiarareclassigeneriche
class Name<TypeVar1, …, TypeVarN> {…} interface Name<TypeVar1, …, TypeVarN> {…}
o convenzionistandardTperType,EperElement,KperKey,VperValue,…
IstanziareunaclassegenericasignificafornireunvalorediApo
Name<Type1, …, TypeN>
5
IstanziareApi
boolean add1(Object elt); boolean add2(Number elt); add1(new Date( )); // OK add2(new Date( )); // compile-time error
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
Limitesuperioregerarchia
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
SipossonoeffeVuaretuVeleoperazionicompaAbiliconillimitesuperioredellagerarchia
o conceVualmentequestocorrispondeaforzareunaprecondizionesullaistanziazionedelApo
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 { static <T extends Number> double sumList(List<T> lst) { double result = 0.0; for (Number n : lst) // T also works result += n.doubleValue(); return result; } static <T> T choose(List<T> lst) { int i = … // random number < lst.size return lst.get(i); } }
11
DichiarareivincolisuiApi
DichiarareivincolisuiApi
Metodigenerici
MetodichepossonousareiApigenericidelleclassi
PossonodichiarareancheiloroApigenerici
LeinvocazionidimetodigenericidevonoobbligatoriamenteistanziareiparametridiApoo 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
IntegerèunsoVoApodiNumber
List<Integer>èunsoVoApodiList<Number>?
14
Number
Integer
List<Number>
List<Integer> ?
QualisonoleregolediJava?
SeType2eType3sonodifferenA,eType2èunsoVoApodiType3,alloraType1<Type2>nonèunsoVoApodiType1<Type3>Formalmente:lanozionedisoVoApousatainJavaèinvarianteperleclassigeneriche
15
Esempi(daJava)
TipiesoVoApio IntegerèunsoVoApodiNumbero ArrayList<E>èunsoVoApodiList<E>o List<E>èunsoVoApodiCollecAon<E>
Mao List<Integer>nonèunsoVoApodiList<Number>
16
List<Number>eList<Integer>
interface List<T> { boolean add(T elt); T get(int index); }
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
Number
Integer
Unadiscussione(percapireanchelaricercanelseVore)
interface List<T> { T get(int index); }
typeList<Number>has Number get(int index);
typeList<Integer>has Integer get(int index);
LanozionedisoVoApocovariantesarebbecorreVao List<Integer>soVoApodiList<Number>
SfortunatamenteJavanonadoVaquestasoluzione
18
Number
Integer
Alloraparliamoanchedicontravarianza
interface List<T> { boolean add(T elt); }
typeList<Number>has boolean add(Number elt);
typeList<Integer>has boolean add(Integer elt);
LanozionedisoVoApocontravariantesarebbealtreVantocorreVao List<Number>èsoVoApodiList<Integer>
MaJava...
19
Number
Integer
AltriaspeS
List<Integer>eList<Number>nonsonocorrelaAdallanozionedisoVoApo
TuVavia,indiversicasilanozionedisoVoAposuigenericifunzionacomeunoseloaspeVaancheinJava
Esempio:assumiamocheLargeBagextendsBag,allorao 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);
TropporestriSvoo ilparametroaVualediApoList<Integer>perSet<Number>
nonvabeneancheseaddAllhasolobisognodileggeredacenondimodificarlo!!!
o questaèlaprincipalelimitazionedellanozionediinvarianzaperigenericiinJava
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:unparametrogenericomavincolatoo possoavereunparametroaVualediApoList<Integer>perSet<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
Sintassidellewildcardo ? extends Type,soVoApononspecificatodelApoType o ?notazionesemplificataper? extends Object o ? super Type,superApononspecificatodelApoType
wildcard=unavariabilediApoanonimao ?Apononconosciutoo siusanolewildcardquandosiusaunApoesaVamenteunavoltama
nonsiconosceilnomeo l’unicacosachesisaèl’unicitàdelApo
26
Esempi
interface Set<E> { void addAll(Collection<? extends E> c); }
o maggiormenteflessibilerispeVoavoid 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
?TipoparAcolareanonimovoid 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òmemorizzareGiraffemanonZebre
29
Rawtypes
Conrawtypesiindicaunaclasse/interfacciasenzanessunargomentodiApo(legacycode)
30
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
InferenzadiApo
Inferenza:capacitàdicontrollareunainvocazionedimetodoeladichiarazionedimetodoassociataalfinedideterminareilApopiùspecifico,inaccordoaivincolidiApopresenA,cherendeilmetodoeffeSvamenteinvocabile
31
class MyClass<S> { <T> MyClass(T t) { ... } }
new MyClass<Integer>("")
MyClass<Integer> myObject = new MyClass<>("")
diamondnotaAon
Ancoral’inferenzadiApo
32
static <T> List<T> emptyList();
List<String> listOne = Collections.<String>emptyList();
List<String> listOne = Collections.emptyList();
void processStringList(List<String> stringList) { ... }
processStringList(Collections.<String>emptyList());
processStringList(Collections.emptyList());
metodoinCollecAons
obbligatorioInJava7Java8inferiscedalApodelparametro
Javaarray
SappiamobenecomeoperarecongliarrayinJava…Vero?
Analizziamoquestaclasseclass Array<T> { public T get(int i) { … "op" … } public T set(T newVal, int i) { … "op" … } } Domanda:SeType1èunsoVoApodiType2,qualeèlarelazionetraType1[]eType2[]??
33
Sorpresa!
SappiamocheperigenericilanozionedisoVoApoèinvariante,pertantoseType1èunsoVoApodiType2,alloraType1[]eType2[]nondovrebberoesserecorrelaA
MaJavaèstrano,seType1èunsoVoApodiType2,alloraType1[]èunsoVoApodiType2[] o Java(maancheC#)hafaVoquestasceltaprimadell’introduzionedei
genericio cambiarlaoraèunpo’troppoinvasivoperipigriprogrammatoriJava
(commentoobbligatoperchifaricercasuiprincipideilinguaggidiprogrammazione)
34
Cisonoanchecose“buone”
Gliinglesidicono:“Programmersdookaystuff”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
LibraryHolding
Book CD
Mapuòandaremale
void replace17(LibraryHolding[ ] arr, LibraryHolding h) { arr[17] = h; }
// 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
LibraryHolding
Book CD
LesceltediJava
IlApodinamicoèunsoVoApodiquellostaAcoo violatonelcasodiBook b
LasceltadiJavao ogniarray“conosce”ilsuoApodinamico(Book[ ])o modificarea(run-Ame)conununsuperApodeterminaArrayStoreException
pertantoreplace17sollevaunaeccezioneo EveryJavaarray-updateincludesrun-,mecheck
! (dallaspecificadellaJVM)o Morale:fateaVenzioneagliarrayinJava
37
Toogoodtobetrue:typeerasure
TuSiApigenericisonotrasformaAinObjectnelprocessodicompilazioneo moAvo:backward-compaAbilityconilcodicevecchioo morale:arunAme,tuVeleistanziazionigenerichehannolostessoApoList<String> lst1 = new ArrayList<String>( ); List<Integer> lst2 = new ArrayList<Integer>( ); lst1.getClass( ) == lst2.getClass( ) // true
38
GenericiecasAng
List<?> lg = new ArrayList<String>( ); // ok List<String> ls = (List<String>) lg; // 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; Node<E> n = (Node<E>) obj; return this.data( ).equals(n.data( )); } ... }
40
Erasure:Apodell’argomentononesistearunAme
equals
class Node<E> { ... @Override public boolean equals(Object obj) { if (!(obj instanceof Node<?>)) return false; Node<E> n = (Node<E>) obj; return this.data( ).equals(n.data( )); } ... }
41
Erasure:arunAmenonsisacosasiaE
Tips(dastackoverflow)
StartbywriAngaconcreteinstanAaAono getitcorrect(tesAng,reasoning,etc.)o considerwriAngasecondconcreteversion
Generalizeitbyaddingtypeparameterso thinkaboutwhichtypesarethesameordifferento thecompilerwillhelpyoufinderrors
42
JavaGenerics(JG)
Ilcompilatoreverifical’uAlizzocorreVodeigenerici IparametridiAposonoeliminaAnelprocessodicompilazioneeil“classfile”risultantedallacompilazioneèunnormaleclassfilesenzapoliformismoparametrico
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
JGaiutanoamigliorareilpolimorfismodellasoluzione Limiteprincipale:ilApoeffeSvoèpersoarunAmeacausadellatypeerasure TuVeleistanziazionisonoidenAficate EsistonoaltreimplementazionideigenericiperJava
GenericseJava
JG/Pizza Bracha, Odersky, Stoutamire, Wadler
NextGen Cartwright, Steele
PolyJ Bank, Liskov, Myers
Agesen, Freund, Mitchell
Generic CLR Kennedy, Syme
Parameterized types !
+ bounds !
+ bounds !
+ constraints !
+ bounds !
+ bounds
Polymorphic methods ! ! " " ! Type checking at point of definition ! ! ! " ! Non-reference instantiations " " ! ! ! Exact run-time types " ! ? ! ! Polymorphic virtual methods " ! " " ! Type parameter variance " ! " " "
System
Feature
Unaan7cipazionediprogrammazioneavanzata
GenericC#
KennedyandSymehaveextendedCLRtosupportparametrictypes(thesameproposalhasbeenmadeforPolyJbyCartwrightandSteele) Theverifier,JITandloaderhavebeenchanged WhentheprogramneedsaninstanAaAonofagenerictypetheloadergeneratestheappropriatetype TheJITcanshareimplementaAonofreferenceinstanAaAons(Stack<String>hasessenAallythesamecodeofStack<Object>)
GenericC#compiler
GC#compilerimplementsaJGlikenotaAonforparametrictypes BoundsarethesameasinJG NOtype-inferenceongenericmethods:thetypemustbespecifiedinthecall ExactrunAmetypesaregrantedbyCLRsovirtualgenericmethodsareallowed Alltypeconstructorscanbeparameterized:struct,classes,interfacesanddelegates
Esempio
.field private !0[] v
.method private hidebysig specialname
rtspecialname instance void .ctor() cil
managed { .maxstack 2 ldarg.0 call instance void
[mscorlib]System.Object::.ctor()
ldarg.0 ldc.i4.s 15 newarr !0 stfld !0[] class n.Foo<!
0>::v ret } // end of method Foo::.ctor
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); } } }