Upload
others
View
2
Download
0
Embed Size (px)
Citation preview
Morethanyoueverwantedtoknowabout
JavaGenericsJeffMeister
CMSC420Summer2007
GENERICS:AYOUNGLADY’SILLUSTRATEDPRIMERINFOURSLIDES
Theobligatoryreviewoftheboringstuff,or…
Java1.4:LifeBeforeGenerics
Javacodeusedtolooklikethis:
ListlistOfFruits=newArrayList();listOfFruits.add(newFruit(“Apple”));Fruitapple=(Fruit)listOfFruits.remove(0);listOfFruits.add(newVegetable(“Carrot”));//Whoops!Fruitorange=(Fruit)listOfFruits.remove(0);//Run‐timeerror
Problem:Compilerdoesn’tknowlistOfFruits shouldonlycontainfruits
ASillySoluMon
Wecouldmakeourownfruit‐onlylistclass:
classFruitList{voidadd(Fruitelement){…}Fruitremove(intindex){…}…}
Butwhataboutwhenwewantavegetable‐onlylistlater?Copy‐paste?Lotsofbloated,unmaintainablecode?
Java1.5:NowWe’reTalking
Now,Javacodelookslikethis:
List<Fruit>listOfFruits=newArrayList<Fruit>();listOfFruits.add(newFruit(“Apple”));Fruitapple=listOfFruits.remove(0);listOfFruits.add(newVegetable(“Carrot”));//Compile‐timeerror
Hooray!CompilernowknowslistOfFruitscontainsonlyFruits
• Soremove()mustreturnaFruit• Andadd()cannottakeaVegetable
Youguysrememberthis,right?
Here’showwe’dwritethatgenericListclass:
classList<T>{voidadd(Telement){…}Tremove(intindex){…}…}
Problemsolved!SimplyinvokeList<Fruit>,List<Vegetable>,andsoon.I’msureyou’vewri^encodelikethisbefore,solet’smoveto…
THEFUNSTUFFHopeyouplannedonbeingconfusedtoday,becauseit’sMmefor…
AbandonAllHope…
• Genericsimplementparametricpolymorphism– Parametric:Thetypeparameter(e.g.,<T>)…– Polymorphism:…cantakemanyforms
• However,ifwe’regoingtoprogramwithparameterizedtypes,weneedtounderstandhowthelanguagerulesapplytothem
• Javagenericsareimplementedusingtypeerasure,whichleadstoallsortsofwackyissues,aswe’llsee
Subtyping
SinceAppleisasubtypeofObject,isList<Apple>asubtypeofList<Object>?
List<Apple>apples=newArrayList<Apple>();List<Object>objs=apples;//Doesthiscompile?
Seemsharmless,butno!Ifthatworked,wecouldputOrangesinourList<Apple>likeso:
objs.add(newOrange());//OKbecauseobjsisaList<Object>Applea=apples.remove(0);//WouldassignOrangetoApple!
AnAside:SubtypingandJavaArrays
• Javaarraysactuallyhavethesubtypingproblemjustdescribed(theyarecovariant)
• Thefollowingobviouslywrongcodecompiles,onlytofailatrun‐Mme:
Apple[]apples=newApple[3];Object[]objs=apples;//Thecompilerpermitsthis!objs[0]=newOrange();//ArrayStoreException
• Avoidmixingarraysandgenerics(trustme)
WildcardTypes
• So,whatisList<Apple>asubtypeof?• ThesupertypeofallkindsoflistsisList<?>,theListofunknown
• The?isawildcardthatmatchesanything
• Wecan’taddthings(exceptnull)toaList<?>,sincewedon’tknowwhattheListisreallyof
• ButwecanretrievethingsandtreatthemasObjects,sinceweknowtheyareatleastthat
BoundedWildcards
• Wildcardtypescanhaveupperandlowerbounds
• AList<?extendsFruit>isaListofitemsthathaveunknowntypebutareallatleastFruits– SoitcancontainFruitsandApplesbutnotPeas
• AList<?superFruit>isaListofitemsthathaveunknowntypebutareallatmostFruits– SoitcancontainFruitsandObjectsbutnotApples
BoundedWildcardsExampleclassWholesaleVendor<T>{voidbuy(inthowMany,List<?superT>fillMeUp){…}voidsell(List<?extendsT>emptyMe){…}…}
WholesaleVendor<Fruit>vendor=newWholesaleVendor<Fruit>();List<Food>stock=…;List<Apple>overstockApples=…;
//IcanbuyFoodfromtheFruitvendor:vendor.buy(100,stock);//IcansellmyApplestotheFruitvendor:vendor.sell(overstockApples);
JoshBloch’sBoundedWildcardsRule
• Use<?extendsT>whenparameterizedinstanceisaTproducer(forreading/input)
• Use<?superT>whenparameterizedinstanceisaTconsumer(forwriMng/output)
Uhh…what?
GenericMethods
• Youcanparameterizemethodstoo.Here’sasignaturefromtheJavaAPI:
static<T>voidfill(List<?superT>list,Tobj);
• Easyenough,yeah?Trythisoneonforsize:static<TextendsObject&Comparable<?superT>>T
max(Collection<?extendsT>coll);
• Youdon’tneedtoexplicitlyinstanMategenericmethods(thecompilerwillfigureitout)
HowGenericsareImplemented
• RatherthanchangeeveryJVMbetweenJava1.4and1.5,theychosetouseerasure
• Agerthecompilerdoesitstypechecking,itdiscardsthegenerics;theJVMneverseesthem!
• Itworkssomethinglikethis:– TypeinformaMonbetweenanglebracketsisthrownout,e.g.,List<String>List
– Usesoftypevariablesarereplacedbytheirupperbound(usuallyObject)
– Castsareinsertedtopreservetype‐correctness
ProsandConsofErasure
• Good:BackwardcompaMbilityismaintained,soyoucansMlluselegacynon‐genericlibraries
• Bad:Youcan’tfindoutwhattypeagenericclassisusingatrun‐Mme:
classExample<T>{voidmethod(Objectitem){if(iteminstanceofT){…}//Compilererror!TanotherItem=newT();//Compilererror!T[]itemArray=newT[10];//Compilererror!}}
UsingLegacyCodeinGenericCode
• SayIhavesomegenericcodedealingwithFruits,butIwanttocallthislegacylibraryfuncMon:
SmoothiemakeSmoothie(Stringname,Listfruits);
• IcanpassinmygenericList<Fruit>forthefruitsparameter,whichhastherawtypeList.Butwhy?Thatseemsunsafe…makeSmoothie()couldsMckaVegetableinthelist,andthatwouldtastenasty!
RawTypesandGenericTypes
• Listdoesn’tmeanList<Object>,becausethenwecouldn’tpassinaList<Fruit>(subtyping,remember?)
• Listdoesn’tmeanList<?>either,becausethenwecouldn’tassignaListtoaList<Fruit>(whichisalegaloperaMon)
• Weneedbothofthesetoworkforgenericcodetointeroperatewithlegacycode
• Rawtypesbasicallyworklikewildcardtypes,justnotcheckedasstringently– TheseoperaMonsgenerateanuncheckedwarning
TheProblemwithLegacyCode
• “Callinglegacycodefromgenericcodeisinherentlydangerous;onceyoumixgenericcodewithnon‐genericlegacycode,allthesafetyguaranteesthatthegenerictypesystemusuallyprovidesarevoid.However,youaresMllbe^eroffthanyouwerewithoutusinggenericsatall.Atleastyouknowthecodeonyourendisconsistent.”–GiladBracha,JavaGenericsDeveloper
MyAdviceonGenerics
• Don’ttrytothinkaboutgenericcodeabstractly;makeanexampleinstanMaMoninyourheadandrunthroughscenariosusingit
• Genericsareavaluabletooltoensuretypesafety,sousethem!Letthecompilerhelpyou
• However,genericsalsocomplicatesyntax,andtheycangeneratesomenastyerrorsthatareapaintounderstandanddebug
AnAnalogy:FuncMons
• Problem:IwanttoperformthesamecomputaMononmanydifferentinputvalueswithoutwriMngthecomputaMonoverandover.
• SoluMon:WriteafuncMon!Useavariabletorepresenttheinputvalue,andwriteyourcodetoperformthecomputaMononthisvariableinawaythatdoesnotdependonitsvalue.NowyoucancallthefuncMonmanyMmes,passingindifferentvaluesforthevariable.Easystuff.
GenericsProvideAnotherAbstracMon
• Problem:Iwanttousethesameclass(ormethod)withobjectsofmanydifferenttypeswithoutwriMngtheclassoverandoverorsacrificingtypesafety.
• SoluMon:Generifytheclass!UseavariableTtorepresenttheinputtype,andwriteyourcodetooperateonobjectsoftypeTinawaythatdoesnotdependontheactualvalueofT.NowyoucaninstanMatetheclassmanyMmes,passingindifferenttypesforT.
• See?It’snotsobad.Genericsjustallowyoutoabstractovertypesinsteadofvalues.