301aa - advanced programming [ap-2017] -...
Post on 10-Mar-2018
217 Views
Preview:
TRANSCRIPT
301AA-AdvancedProgramming[AP-2017]
Lecturer:AndreaCorradiniandrea@di.unipi.itTutor:LilloGalleBagalleBa@di.unipi.it
DepartmentofComputerScience,PisaAcademicYear2017/18
AP-2017-14: JavaGenerics
Outline
• Javagenerics• Typebounds• Genericsandsubtyping• Covariance,contravarianceinJavaandotherlanguages
• SubtypingandarraysinJava• Wildcards• Typeerasure• LimitaQonsofgenerics
2
ClassificaQonofPolymorphism
Polymorphism
Universal
Ad hoc
Parametric
Inclusion
Overloading
Coercion Implicit
Bounded
Overriding
Explicit
Covariant
Invariant
Contravariant
Bounded
JavaGenerics
• Classes,Interfaces,Methodscanhavetypeparameters
• ThetypeparameterscanbeusedarbitrarlyinthedefiniQon
• TheycanbeinstanQatedbyprovidingarbitrary(reference)typearguments
• WediscussonlyafewissuesaboutJavagenerics…
4
List<Integer> List<Number> List<String> List<List<String>> …
interface List<E> { boolean add(E n); E get(int index); }
ExplicitParametricPolymorphism
TutorialsonJavagenerics:https://docs.oracle.com/javase/tutorial/java/generics/index.html!http://thegreyblog.blogspot.it/2011/03/
! !java-generics-tutorial-part-i-basics.html!
Genericmethods
• Methodscanusethetypeparametersoftheclasswheretheyaredefined,ifany
• Theycanalsointroducetheirowntypeparameters
public static <T> T getFirst(List<T> list)!
!• InvocaQonsofgenericmethodsmustinstanQateall
typeparameters,eitherexplicitlyorimplicitly– Aformoftypeinference
5
BoundedTypeParameters interface List<E extends Number> { void m(E arg) { arg.asInt(); // OK, Number and its subtypes // support asInt() } }
• OnlyclassesimplemenQngNumbercanbeusedastypearguments
• Methoddefinedinthebound(Number)canbeinvokedonobjectsofthetypeparameter
6
TypeBounds<TypeVar extends SuperType> – upperbound;SuperTypeandanyofitssubtypeareok.
<TypeVar extends ClassA & InterfaceB & InterfaceC & …> – Mul4pleupperbounds
<TypeVar super SubType> – lowerbound;SubTypeandanyofitssupertypeareok
• TypeboundsformethodsguaranteethatthetypeargumentsupportstheoperaQonsusedinthemethodbody
• UnlikeC++whereoverloadingisresolvedandcanfailaderinstanQaQngatemplate,inJavatypecheckingensuresthatoverloadingwillsucceed
7
Agenericalgorithmwithtypebounds
8
public static <T> int countGreaterThan(T[] anArray, T elem) {! int count = 0;! for (T e : anArray)! if (e > elem) // compiler error! ++count;! return count;!}!
public interface Comparable<T> { !// classes implementing! public int compareTo(T o); !// Comparable provide a !} ! !// default way to compare their objects!
public static <T extends Comparable<T>> !! ! ! !int countGreaterThan(T[] anArray, T elem) {!
int count = 0;! for (T e : anArray)! if (e.compareTo(elem) > 0) !// ok, it compiles! ++count;! return count;!}!
Genericsandsubtyping
• IntegerissubtypeofNumber!
• IsList<Integer>subtypeofList<Number>?
• NO!
9
Number
Integer
List<Number>
List<Integer>?
WhatareJavarules?• GiventwoconcretetypesAandB,MyClass<A>hasno
rela9onshiptoMyClass<B>,regardlessofwhetherornotAandBarerelated.
• Formally:subtypinginJavaisinvariantforgenericclasses.
• Note:ThecommonparentofMyClass<A>andMyClass<B>isMyClass<?>:the“wildcard”?Willbediscussedlater.
• Ontheotherhand,asexpected,ifAextendsBandtheyaregenericclasses,foreachtypeCwehavethatA<C>extendsB<C>.
• Thus,forexample,ArrayList<Integer>issubtypeofList<Integer>
10
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);
IstheSubs9tu9onPrinciplesaQsfiedineitherdirecQon?ThusList<Number>isneitherasupertypenorasubtypeofList<Integer>:Javarulesareadequatehere 11
Number
Integer
List<Integer> lisInt = new …;!List<Number> lisNum = new …; !lisNum = lisInt; !// ???!lisNum.add(new Number(…));//no!listInt = lisNum; !// ???!Integer n = lisInt.get(0); //no!
ButinmorespecificsituaQons…interface List<T> { T get(int index); }
typeList<Number>: Number get(int index);
typeList<Integer>: Integer get(int index);
Acovariantno9onofsubtypingwouldbesafe:– List<Integer>canbesubtypeofList<Number> – NotinJava
• Ingeneral:covarianceissafeifthetypeisread-only
12
Number
Integer
Viceversa…contravariance!interface List<T> { boolean add(T elt); }
typeList<Number>: boolean add(Number elt);
typeList<Integer>: boolean add(Integer elt);
Acontravariantno9onofsubtypingwouldbesafe:
– List<Number>canbeasubtypeofList<Integer> – ButJava…..
Ingeneral:contravarianceissafeifthetypeiswrite-only
13
Number
Integer
GenericsandsubtypesinC#• InC#,thetypeparameterofagenericclasscanbe
annotatedout(covariant)orin(contravariant),otherwiseitisinvariant.Examples:
• Ienumeratoriscovariant,becausetheonlymethodreturnsanenumerator,whichaccessesthecollecQoninread-only
• IComparableiscontravariant,becausetheonlymethodhasanargumentoftypeT
14
public interface IEnumerable<out T> : […] {!!public […]IEnumerator<out T> GetEnumerator ();!
}!
public interface IComparable<in T> {!!public int CompareTo (T other);!
}!
Co-andContra-varianceinScala
• AlsoScalasupportsco/contra-varianceannotaQons(-and+)fortypeparameters:
!class VendingMachine[+A]{…}!!class GarbageCan[-A]{…}!!trait Function1[-T, +R] extends AnyRef !{ def apply(v1: T): R }!
15
http://blog.kamkor.me/Covariance-And-Contravariance-In-Scala/!
Adigression:Javaarrays
• Arraysarelikebuilt-incontainers– LetType1beasubtypeofType2.– HowareType1[]eType2[]related?
• Considerthefollowinggenericclass,mimickingarrays:class Array<T> {! public T get(int i) { … “op” … }! public T set(T newVal, int i) { … “op” … }!}!AccordingwithJavarules,Array<Type1>andArray<Type2>arenotrelatedbysubtyping
16
Butinstead…
• InJava,ifType1isasubtypeofType2,thenType1[]isasubtypeofType2[].ThusJavaarraysarecovariant.
• Java(andalsoC#,.NET)fixedthisrulebeforetheintroducQonofgenerics.
• Why?Thinkto• Notconvenienttochangeitbecauseofretro-compabilityconsideraQons.
• Covarianceworksfine,providedyoudonotchangethecontentofanarray…
17
void sort(Object[] o);!
Asafeuseofcovarianceinarraysvoid maybeSwap(LibraryHolding[] arr) { if(arr[17].dueDate() < arr[34].dueDate()) // … swap arr[17] and arr[34] } // client Book[] books = …; maybeSwap(books); // uses covariance of arrays
18
LibraryHolding
Book CD
ButinserQoncausesfailure
void replace17(LibraryHolding[] arr, LibraryHolding h) { arr[17] = h; }
// the client Book[] books = …; LibraryHolding theWall = new CD("Pink Floyd", "The Wall", …); replace17(books, theWall); Book b = books[17]; // contains a CD b.getChapters(); // problem!!
19
LibraryHolding
Book CD
Java’schoices• Foreachreferencevariable,thedynamictype(typeoftheobject
referredbyit)mustbeasubtypeofthesta9cone(typeofdeclaraQon).– ViolatedforBook b
• Javadesignchoices:– ThedynamictypeofanarrayisknownatrunQme(Book[],or
beBer[Lmypackage.Book;inJVMtypesyntax)– EveryJavaarray-updateincludesrun-9mecheck– AssigninganobjectofasupertypetoanarraythrowsanArrayStoreException
• Thusreplace17throwsanexcepQon
20
Asimplerexample
21
Apple[] apples = new Apple[1];!Fruit[] fruits = apples;!fruits[0] = new Strawberry();! // JVM throws ArrayStoreException !
Aseriousconsequence• EveryJavaarray-updateincludesrun-Qmecheck,but• GenerictypesarenotpresentatrunQmeduetotypeerasure,thus
• ArraysofgenericsarenotsupportedinJava• InfacttheywouldcausetypeerrorsnotdetectableatrunQme,breakingJavastrongtypesafety
22
List<String>[] lsa = new List<String>[10]; // illegal!Object[] oa = lsa; // OK by covariance of arrays !List<Integer> li = new ArrayList<Integer>();!li.add(new Integer(3));!oa[0] = li; // should throw ArrayStoreExeception, ! !// but JVM only sees “oa[0]:List = li:ArrayList”!String s = lsa[0].get(0); // type error !!!
Wildcardsforcovariance
• InvarianceofgenericclassesisrestricQve• Wildcardscanalleviatetheproblem• Whatisa“generalenough”typeforaddAll?
interface Set<E> { // Adds to this all elements of c // (not already in this) void addAll(??? c); }
• void addAll(Set<E> c) // andList<E>? • void addAll(Collection<E> c)
// andcollecQonsof T <: E? • void addAll(Collection<? extends E> c); // ok 23
Wildcards,forbothco-andcontra-variance
Syntaxofwildcards:– ? extends Type,denotesanunknownsubtypeofType – ?,shorthandfor? extends Object – ? super Type,denotesanunknownsupertypeofType
wildcard=anonymousvariable– ?Unknowntype– Wildcardareusedwhenatypeisusedexactlyonce,andthenameis
unknown– Theyareusedforuse-sitevariance(notdeclara9on-sitevariance)
24
The“PECSprinciple”:ProducerExtends,ConsumerSuper
Whenshouldwildcardsbeused?– Use? extends Twhenyouwanttogetvalues(fromaproducer):supportscovariance
– Use? super Twhenyouwanttoinsertvalues(inaconsumer):supportscontravariance
– Donotuse?(Tisenough)whenyoubothobtainandproducevalues.
Example: <T> void copy(List<? super T> dst, List<? extends T> src);
25
Whatabouttypesafety?
• Arrayscovariance:
• Covariancewithwildcards:
26
Apple[] apples = new Apple[1];!Fruit[] fruits = apples;!fruits[0] = new Strawberry();! // JVM throws ArrayStoreException !
List<Apple> apples = new ArrayList<Apple>();!List<? extends Fruit> fruits = apples;!fruits.add(new Strawberry()); !
!// compile-time error!!!!
Thepricetopaywithwildcards• Awildcardtypeisanonymous/unknown,andalmostnothingcanbedone:
27
List<Apple> apples = new ArrayList<Apple>();!List<? extends Fruit> fruits = apples; //covariance!fruits.add(new Strawberry()); // compile-time error! OK!Fruits f = apples.get(0); // OK!fruits.add(new Apple()); // compile-time error??? !fruits.add(null); //ok, the only thing you can add ! !
List<Fruit> fruits = new ArrayList<Fruits>();!List<? super Apples> apples = fruits; //contravariance!fruits.add(new Apple()); // OK!fruits.add(new FujiApple()); // OK!fruits.add(new Fruit()); // compile-time error, OK!Fruits f = apples.get(0); // compile-time error???!Object o = apples.get(0); //ok, the only way to get!
Typeerasure
AlltypeparametersofgenerictypesaretransformedtoObjectortotheirfirstboundadercompilaQon– MainReason:backwardcompaQbilitywithlegacycode
– Thusatrun-Qme,alltheinstancesofthesamegenerictypehavethesametype
List<String> lst1 = new ArrayList<String>(); List<Integer> lst2 = new ArrayList<Integer>(); lst1.getClass() == lst2.getClass() // true 28
LimitaQonsofJavaGenerics• CannotInstanQateGenericTypeswithPrimiQveTypesArrayList<int> a = … //does not compile• CannotCreateInstancesofTypeParameters• CannotDeclareStaQcFieldsWhoseTypesareTypeParameterspublic class C<T>{ public static T local; …}!• CannotUseCastsorinstanceofWithParameterizedTypes(list instanceof ArrayList<Integer>) // does not compile!(list instanceof ArrayList<?>) // ok• CannotCreateArraysofParameterizedTypes• CannotCreate,Catch,orThrowObjectsofParameterizedTypes• CannotOverloadaMethodWheretheFormalParameterTypesofEach
OverloadErasetotheSameRawTypepublic class Example { // does not copile!public void print(Set<String> strSet) { } !public void print(Set<Integer> intSet) { } }!
29
top related