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