Transcript

Chapter7Inheritance

ClassInheritance:Introductionextendsusage

protectedvisibilityabstractclasses/methods

Hello!Besuretoactuallyworkthroughtheexamplesinorder;the"YourTurn"problemsbuilduponeachotherextensively.TodaywewillcoveranotherkeyOOconcept:inheritance.We'recomfortablewithallthestructureandhierarchyofcreatingseparateclasses,usingfieldstogetsomeaggregationgoing,butourclassdefinitionsarestillallwrittenseparately.Inheritanceisgoingtoallowustowriteclassesbyessentiallyborrowingallofanotherclass'sdefinition,andselectivelyaddingmorefieldsandmethodstoit,withsomeniftyrelationshipsholdingbetweentheoriginalandnewly-definedclasses.MotivationSofar,theonlywaywecouldcausetwoclassestointeractinanywaywasthroughaggregation:wheretheobjectofoneclass"HAS-A"objectofanotherclassaspartofitsowndata.Let'squicklyreviewanexampleofaggregation,becauseweneedtobesurewecontrasttheideaofaggregationwiththenewconceptofinheritance.AggregationExample:ASphereHAS-ACoordinate:public class Coordinate { public double x,y,z; public Coordinate (int a, int b, int c) { x=a; y=b; z=c; } } public class Sphere { private Coordinate location; private in radius; public Sphere (int r, int x, int y, int z){ radius = r; location = new Coordinate(x,y,z); } }

Aparticularspherehasitsownlocation.EachtimewecreateaSphereobject,wewillhaveaCoordinateobjectaswell.Althoughweseethataninstanceofoneclass(aSphere)hasareferencetoaninstanceofanotherclass(aCoordinate),neitherclassdefinitionisamorespecificversionoftheother.ASphereisn'taCoordinate,eventhoughaSpherehas-aCoordinate;aCoordinateisn'taSphere.Similarly,Sphereisn'tadouble,eventhoughitmayhaveonetorepresenttheradius.

InheritanceTheclassesthemselveseachrepresentatypethatisentirelyseparatefromanythingelse:ASphereobjecthas-aradius,andithas-aCoordinateobject,butnothingrelatesourSphereclasstoaShapeclassoraCubeclass.Wewanttostartidentifyingdifferentclassdefinitionsthatshouldsomehowbelinkedtogether,definedsomehowviathesamecode.WhenWouldIWantInheritance?Considerthefollowingthreeclassdefinitions.Wearecreatinga(verysimple)programtouseoncampus,andwanttostoreinformationaboutvariouspeopleoncampus.Wehavestudents,employees,andothernon-specificpersons.public class Person { private String name; private int age; //methods: (constructors), getName, setName, getAge, setAge. } public class Student { private String name, major; private int age, masonID, yearsOnCampus; /* methods: (constructors), getName, setName, getMajor, setMajor, getAge, setAge, getMasonID, setMasonID, getYearsOnCampus, setYearsOnCampus. */ }

public class Employee { private String name, jobTitle; private int age, masonID, yearsOnCampus; /* methods: (constructors), getName, setName, getJobTitle, setJobTitle, getAge, setAge, getMasonID, setMasonID, getYearsOnCampus, setYearsOnCampus. */ }

Weseesomeoverlapinthesedefinitions:alloftheseclasseshaveanameandage.SomeoftheclasseshavemasonIDandyearsOnCampusvariables.Andafewothervariablesareuniquetodifferentclasses(major,jobTitle).Nowimaginethatweaddedconstructors,getters,andsettersforeachoftheseinstancevariables.We'dseemoreandmoreduplicatedcode,bothindataandbehaviors(methods).Wecancreatemultipleobjectsfromeachoftheseclasses:Student s1 = new Student( "Bob", "art", 19, 71922, 2 ); Student s2 = new Student( "Helen", "education", 18, 71923, 1 ); Person[] people = { new Person("A",1) , new Person("B",2) , new Person("C",3) }; Employee e1 = new Employee ("Catherine", "cashier", 35, 71985, 7); Butthere'saproblem:wecan'tactuallyusethesedefinitionstogetherverywell.Supposewewantedtorepresentthepeopleinlineatthecashregisterinthefoodcourt:Person pers = new Person ("Sally", 25); Student stud = new Student ("Buddy", "undeclared", 21, 71234,2); Employee emp = new Employee ("Doug", "HR", 41, 72468, 10); SomeType[] customers = {pers, stud, emp}; // BAD CODE ????????

WhattypeshouldweputforSomeType?Wecan'tchooseanyofPerson,Student,Employee,becausethere'ssomethinginthearraythatdoesn'tmatchthetype.Theproblemisthelackofarelationbetweenthesedifferenttypes:thereisnowayforustotreataStudentlikeaPerson.EventhoughaStudenthasalltheinstancevariablesaPersonhas,andhasallthemethodsaPersonhas,wecan'ttreataStudentlikeaPerson.JavahasnoideathatitissafetotreataStudentlikeaPerson.Howimpersonal!Similarly,wecan'ttreatanEmployeelikeaPersoneither.DouginHRisgoingtohearmycomplaintsaboutthisworkenvironment.WewanttogiveJavatheinformationsothatthesedifferentclassesarelinkedtogether:wewanttobeabletosayaStudentIS-APerson,andthatanEmployeeIS-APerson.

So:wewanttorelatethesedifferentclassdefinitionsbyactuallydefiningoneclassintermsofanother.WewanttoreusethePersondefinition,andextendittotellJavahowaStudentisamore-specificversionofaPerson,andhowanEmployeeisamore-specificversionofaPerson.

public class Person { private String name; private int age; //methods: (constructors), getName, setName, getAge, setAge. } public class Student extends Person { // we inherit name and age. private String major; private int masonID, yearsOnCampus; /* methods that we write: (constructors), getMajor, setMajor, getMasonID, setMasonID, getYearsOnCampus, setYearsOnCampus. */ } public class Employee extends Person { // we inherit name and age. private String jobTitle; private int masonID, yearsOnCampus; /* methods: (constructors), getJobTitle, setJobTitle, getMasonID, setMasonID, getYearsOnCampus, setYearsOnCampus. */ }

Let'sstopandthinkamomentaboutourtwousesofextends Person.Student extends Person.Byaddingthosetwowords(extends Person),wearetellingJavathataStudentisaPerson.ThatmeansthatallthedataaPerson has,aStudent hasthatdata,too.AllthebehaviorsthataPersoncanexhibit,aStudentcanexhibittoo.Wedon'texplicitlylistString name andint age intheStudentclass,buteachStudentobjectwillhavetheseinstancevariables,becauseaStudentisaPersonandaPersonhasanameandage.Similarly,allthemethodsthatweredefinedinthePersonclass(e.g.,getName,setAge)arealsoavailabletoStudentobjects,becauseaStudentisaPerson.Whenwedrawthememoryusageforobjectsonthewhiteboardwithacircleencompassingallthedataandmethods,wewouldnowdrawaStudentobjectbydrawingaPersonobject,andthenaddinginthemajor,masonID,andyearsOnCampusinstancevariablestothedataportion(tophalf),andaddingtheextra

methoddefinitionstothebehaviorssection(bottomhalf).Again,notethatallwedowithsubclassesisadddefinitions,nevertakeaway.Thiscrucialonly-adding-thingspropertyiswhywe'reabletosaythateverysingleStudentobjectcanalwaysbeusedasaPersonobject.It'sasifwetemporarilyignoretheextravariablesandmethodsthatStudentshave,andjustrelyontheinheritedportions.

Inthediagram,weseethattheStudentobjecthasallthePersonfields(age,name),followedbytheextrafieldsspecifictoStudents(major,masonID,yearsOnCampus).Similarly,ithasallthePersonmethods,followedbyallthespecificStudentmethods(getters/settersformajor,masonID,andyearsOnCampus).IfweignoredpartsoftheStudentobject,itwouldlookjustlikeaPersonobject.ThisistheguaranteethatJavaisgivenwhenweextendaclasstocreateamorespecificversionofit.SomeTerminologyWehavealotofdescriptivewaystodescribetherelationshipbetweenStudentandPerson.

• WecansaythattheStudentclassisasubclassofthePersonclass,orthatPersonisasuperclassofStudent.

• WecanalsocallStudentachild-classofPerson,andPersontheparent-classofStudent.• WecanalsosaythatStudentisasubtypeofPerson,andPersonisasupertypeofStudent.

Usingtheis-aRelationship.Sohowcanweactuallyusethis"Studentis-aPerson"relationship?Considerthefollowinglegalcode(oncewe'veactuallywrittentheconstructors):Person p = new Person ("A",1); Student s = new Student("B", "CS", 20, 71235, 3); System.out.println("p name: " + p.getName()); System.out.println("s name: " + s.getName()); p = s; System.out.println("p name: " + p.getName()); ThepvariablecanonlyholdareferencetoaPersonobject.ButaStudentis-aPerson,sopcanalsoholdareferencetoaStudent,becausethatmeansitalsohappenstobestoringareferencetosomethingthatis-aPerson.Now,backtoourregisterexample.WenowknowthataPersonis-aPerson,aStudentis-aPerson,andanEmployeeis-aPerson.Soit'ssafetouseanarrayofPersonreferencestostoreourvariousvalues:Person[] customers = {pers, stud, emp}; YourTurn!

Createfilesforallthreeoftheaboveclasses.Fornow,don'twriteconstructorsyet;relyontheannoyingdefaultconstructors.Thatmeanswehavetocreateourobjectsthisway:Person p = new Person(); p.setName("Bob"); p.setAge("20"); Student s = new Student(); s.setName("Jane"); s.setAge(19); s.setMajor("art"); …

• Caution:ifyouaccidentallyaddnameandagefieldstoStudentorEmployee,Javawillallowit(itiscalledshadowing,andisgenerallyabadideatousethis'feature').Makesurethatyoudon'tre-defineanythingthatissupposedtobeinherited.

• AddanotherclassthatextendsPerson.Choosesomeothertypeofpersonthatwouldbeoncampus:Policeman,Athlete,Professor,orwhatever.EvenifitseemstooverlapwitheitherStudentorEmployee,it'sokay,aslongasthere'sextradatayouwanttokeeptrackofforthisnewtypeofperson.

• Createobjectsofeachofyourclasstypes.(PutthiscodeinTestInheritance.java).Exploreusingthegetters/setters,andseethatyoudoindeedgettousemethodsdeclaredinthePersonclasswhenusingaStudentobject,Employeeobject,andsoon.

• CreateatoStringmethodforjustthePersonclass,andnottheothers.Retestthe"UsingtheIs-ARelationship"code,butjustprintoutpandsinsteadofp.getName()andsoon.Noticethatevenmethodslikethiscanbeinherited.We'llseehowwecandobettertorepresentStudentobjectsthanbeingstuckwiththePerson versionofthetoString implementation.

VisibilityWefinallyhaveachancetoexperiencethelastvisibility:protected.TrywritingatoStringmethodfortheStudentclass.Printalltherelevantinfo.Forexample,trytogetyourtoStringmethodintheStudentclasstooutput:Student{name="foo", major="art", age=19, masonID=1234, years=2} Whatgoeswrong?WegetacomplaintfromtheJavacompilerthatnameandageareprivate.(Assumingyouusedthevisibilitiesshownabove!Iftheknee-jerkreactiontomakeeverythingpublickickedin,justgobacktoPerson,makethoseinstancevariablesprivate,andthenseethechildfailtoaccessit).Eventhoughwe'reinheritingfromthePersonclass,privatestillmeans"onlyaccessibleincodeactuallywritteninthisclassdefinition".Ratherthanmakenameandage public(whichviolatesencapsulationprinciples),weareofferedacompromise:theprotectedvisibility.Thiswillcausename andagetostillbehaveasifitwereprivateinplacessuchasyourtestingcode(insomeotherclasslikeTestInheritance),buttheywillnowbehaveasiftheywerepublicwhenaccessedfromachildclasslikeStudent. YourTurn!

• Changethevisibilityofnameandagetoprotected.o First,verifythatyoustillcan'taccessthemfromTestInheritance.Thisisbecauseit'snota

childclassofPerson.• GobackandwriteyourtoStringmethodintheStudent class.Nowthattheyareprotected,it'sas

iftheyweredeclaredwithpublicvisibilityasfarasthechildclassesareconcerned.o Revisitthe"UsingtheIs-ARelationship"examplefromabove(andstilljustprintpands

ratherthanp.getName()andsoon).Nowit'sevenmoreapparentthatwehaveaStudentobjectbeingusedwhereweexpectaPerson.

OverridingMethodsInthelastexample,wewitnessedsomethingthatisactuallykindofamazing:theStudentclassgottooverridethedefinitionofthetoStringmethod.PersonalreadyprovidedatoStringmethod,whichusedtobewhatourStudentclassused.Butwedecidedwecoulddobetter,andgotridofthatdefinitioninfavorofamorespecificone.Wecanoverridemethodsinheritedfromtheparentclass,withafewrequirements:

• Wehavetheexactsamemethodsignature,andthenwegettosupplyadifferentbody(implementation)forthemethod.

• Theparentclasshastogiveuspermissiontooverrideamethodbynotmakingthemethodfinal.Yes,methodscanbefinal,too–itmeansthatthemethodbodycannotbemodified.Soifwedon'twantre-implementationsofamethodinchildclasses,wejustsaysomethinglike public final int importantMethod(The args) andnowoverridingisnotallowed.

Wheneverourcodecallsthisoverriddenmethodonobjectsofourchildclass,itwillalwaysusethis'better'versionthatweprovided,thusoverridingtheoriginaldefinition.

YourTurn!

• AddthewakeUpTimemethodtothePersonclass,andoverrideitintheStudentclass.(JustreturnaStringforwhetherthispersonwakesupearlyorlate;I'massumingthatstudentsliketosleepin,andemployeesdon'tgetto).

• Testitout(callitonaPerson,andonaStudent).• NowmakethePersonversionofthemethodfinal,andlookforthecompilererror.

WecanactuallytellJavathatweintendtooverrideamethod:justput@Overriderightbeforeamethodthatissupposedtobeonoverridingdefinition.Ifanythinggoeswrong,suchasnotbeingallowedtooverridethemethod,oritturnsoutthatyourmethoddoesn'tactuallyoverrideanymethod,thecompilercannowalertyou.

→whenwouldwenotbeoverridingamethodwhenwethoughtwewere?Consideramethodwithsignature@Override public String tostring() .It'stryingtooverridetoString,butneglectedtocapitalizetheS.

YourTurn!

• addamethodthatisn'tinheritedtoyourStudentclass.Addthe@OverridetagandseethattheJavacompilercatchestheissue.

InheritanceandConstructorsLet'sfinallydiscusshowtomakeconstructorsforchildclasses.Asafirststep,addaniceconstructortothePersonclass:public Person (String name, int age) { this.name = name; this.age = age; } YouwillalsoneedtochangeyourPersoninstantiationstolooklikenew Person ("Bob", 20).Trytore-compile.Specifically,trytorecompilejusttheStudentclass: javac Student.java Whathappens?JavacancreatePersonobjectsusingtheconstructoryouadded,butnowthere'snodefaultconstructor,andsowecan'tevencompiletheStudentclassanymore,whichwasactuallyrelyingonit.OurPersonclassdeclaredthatitwasnolongeracceptabletousethedefaultconstructor,anditexposedthefactthatourStudentconstructoractuallyusedthePersonconstructortocompletethetaskofconstructingaStudentobject.Let'screateaconstructorfortheStudentclass.

First(Bad)Attempt.Let'strytojustwriteaStudentconstructorthatdoesn'trelyonthePersonconstructoratall. //BAD attempt at a child class constructor

public Student (String name, String major, int age, int masonID, int years){ this.name = name; this.major = major; this.age = age; this.masonID = masonID; this.yearsOnCampus = years; } Thisfails;somehow,theJavacompilerstillwantstofindtheconstructorPerson().Itturnsoutwehavetolearnanotherkeyword:super.superissimilarinnaturetothis.Thekeywordthis referstothecurrentobject,givingusaccesstovaluesandmethodsoftheobject.superreferstotheparentclass,givingusaccesstothemembersoftheparentclasswhichweotherwisemaybecouldn'tseeinthechildclass.Ifwewanttoaccessanythingintheparentclass,suchasaspecificconstructormethod,wehavetousesupertoaccessit. // GOOD attempt at a child constructor public Student (String name, String major, int age, int masonID, int years){ //call the parent constructor super(name,age); //finish instantiating things declared in this class. this.major = major; this.masonID = masonID; this.yearsOnCampus = yearsOnCampus; } Thecallsuper(name,age)isactuallycallingtheconstructorofthePersonclassthatacceptsaStringandanint.ThecalltosuperneedstobefirstinourconstructorbodysothatJavaknowswhat'sgoingon.RequiredsupercallsJavarequiresustousetheparentclass'sconstructorwhenwritingourownconstructor.Thisensuresthatourclaimthat"EveryStudentisaPerson"won'tbeviolatedbysomenaïveimplementationofaconstructor.Itturnsoutthatanimplicitsuper()callisaddedtoconstructormethodofchildclassesunlessweaddourownsuper-call.That'swhyourfirstattemptataStudentconstructorfailed:therewasnopublic Person()constructordefinitionanymore.BycreatinganewconstructorforPerson,andthenexplicitlycallingthatnewconstructorwithacalltosuper(some,args),wearefulfillingthe"alwaysuseyourparentclass'sconstructor"requirementwhilealsocompletingtheinstantiationeffortsthatarelocaltoourownclass'sinstancevariables.

YourTurn!

• Createconstructorsforallclasses.Besuretousethenon-defaultconstructorfromthePersonclassbyusingthecorrectsupercalltothePersonconstructorfromyourchildclasses'constructors.

• WhencreatingconstructorsforStudentandEmployee,rememberthatyouhavefiveinstancevariablestoinstantiate(twocamefromthePersonclass,threearedefinedhereintheclass).

• Createallthegettersandsettersfortheinstancevariablesintroducedineachclass.(Remember,theonesdefinedinthePersonclassareinheritedinthechildclasses:youwon'twritegetNameintheStudentclass,butStudentswillinheritthegetName getterthatyoudefineinthePersonclass).Willanythingneedtobemadeprotected insteadofprivate?

AbstractClassesOnelasttopicforinheritanceisthenotionofanabstractclass.Abstractclassesparticipateintheclasshierarchyofparentandchildclasses,butbymakingaclassabstract,wearestatingthatnoobjectsofthisspecificclassmayeverbecreated.(Objectsofchildclasseswouldbepermitted;otherwise,therewouldbenopoint!).Let'sconsideranexampleofanabstractclass.Ifwelooktoouroriginalthreeclasses,wesawaslightchanceformoreoverlap:theStudentandEmployeeclassessharedinstancevariablesmasonIDandyearsOnCampus.Let'screateaclasstohelpusindicatethatrelationshipbyleavingthePersonclassalone,butintroducinganewclassbetweenthePersonclassandthetwochildclassesStudentandEmployee:public class MasonPerson extends Person { protected int masonID; protected int yearsOnCampus; public MasonPerson(String name,int age,int masonID,int years) { super(name, age); this.masonID = masonID; this.yearsOnCampus = years; } }

public class Student extends MasonPerson { protected String major; public Student(String name, String major, int age, int masonID, int years){ //calls MasonPerson constructor super(name,age,masonID,years); this.major = major; } //no more variables, only methods below… } public class Employee extends MasonPerson { protected String jobTitle; public Employee (String name, String job, int age, int masonID, int years){ //calls MasonPerson constructor super(name, age, masonID, years); this.jobTitle = job; } //no more variables, only methods below… }

Onenicethingisthetransitivityofinheritance:becauseaStudentis-aMasonPersonandaMasonPersonis-aPerson,wecantransitivelyclaimthataStudentis-aPerson.Allthedata/behaviorthatMasonPersoninheritsfromPersonwillbepassedontoStudent.Ontoabstractclasses.Suppose,forwhateverreason,thatcreatingaMasonPersondoesn'tmakesense:weonlywanttheretobeobjectsofspecifickindsofpeople:StudentobjectsandEmployeeobjectsareokay,butthevagueideaofaMasonPersononlyhelpsusorganizeourthoughts;anyMasonPersonmustactuallybesomemorespecifictype.WethenchoosetomaketheMasonPersonclassabstract,indicatingthatitisillegaltoinstantiatetheclass:public abstract class MasonPerson extends Person { … } YourTurn!

• AddtheMasonPersonclass,whichextendsthePersonclass.o AddinstancevariablesmasonIDandyearsOnCampus.o Giveitaconstructor,usingthePersonconstructor.

• ChangeStudentandEmployeetobechildclassesofMasonPerson.UpdatetheirconstructorstousetheMasonPersonconstructor.

• InyourTestInheritanceclass,createaMasonPersonobjectandtestitabit.• MakeMasonPersonanabstractclass;re-compileTestInheritanceandseetheerrormessage.→you'vesuccessfullycreatedanabstractclassthatcontributestotheclasshierarchy,yetissafelynotinstantiable(wecan'tcreateobjectsofit).

(keepgoing!Bigchart+descriptionallonthenextpage→)

AnotherAbstractClassesExampleAnalternateexamplecouldbeaprogramrepresentingazoo,whereweusetheKingdom-Phylum-Class-Order-Family-Specieshierarchytoorganizeourclassesofanimals.WewanttohaveclassesforMonkey,Orangutan,Panda,Dolphin,Penguin,Dove,Frog,Alligatorandmoreanimals.Itmakessensetoaddclassestogeneratethefollowinghierarchy:

ItmakessensetohaveMonkey,Panda,andDolphinobjects,butitdoesn'tmakesensetohaveaMammalobjectoraChordataobject.Thoseclassesjusthelpedusorganizethings,andmaybeprovidedefinitionslikenumVertebra,numChromosomes,eggSize,andsoon.Ifwemakealltheblueclassesabstract,theystillparticipateinthehierarchyoftypes(andcancontributefieldsandmethodsforinheriting),butareguaranteedtonotbeinstantiatedthemselves.MoreAbstractThingsWecanusetheabstractkeywordformethods,too.Whatisanabstractmethod?Itisamethodsignaturewithnobody:public abstract int reportNumberOfLegs(); public abstract void moveAround(); Anytimewewanttoindicatethateverychildclassofourabstractclassmusthaveitsownversionofamethod,yetthere'snotgoodstartingimplementationrightnowintheabstractclass,wecancreatean

abstractmethodtorequirethatallchildclassesprovideimplementations(byoverwritingthem).Iftheydon't,theybecomeabstractaswell,guaranteeingthatthismethodwillbeimplementedforanyactualinstanceofaclassthatisachildoftheabstractclassthatintroducedthisabstractmethod.

• Anyclasscontaininganabstractmethodmustbeabstractaswell.• Anyclassthatinheritsanabstractmethodcanimplementitbyoverwritingthatdefinition.• Anyclassthatdoesn'timplementaninheritedabstractmethodthereforestillcontainsanabstract

method,andisthusalsoabstract. YourTurn!

• NowthatMasonPersonisanabstractclass,addanabstractmethodtoit,suchas: public abstract String favoriteFoodSite();

• TryinstantiatingaStudentandseethatit'snowbecomingabstract(well,weseecompilation

erroscomplainingtothateffect).• Overridetheabstractmethodthatwasinherited,andnowweagainareabletoinstantiateour

Studentclass.


Recommended