Tải bản đầy đủ - 0 (trang)
Chapter 5. Nested Classes and Interfaces

Chapter 5. Nested Classes and Interfaces

Tải bản đầy đủ - 0trang

5.1.StaticNestedTypes

Anestedclassorinterfacethatisdeclaredasastaticmember

ofitsenclosingclassorinterfaceactsjustlikeanynon-nested,

ortop-level,classorinterface,exceptthatitsnameand

accessibilityaredefinedbyitsenclosingtype.Thenameofa

nestedtypeisexpressedasEnclosingName.NestedName.Thenested

typeisaccessibleonlyiftheenclosingtypeisaccessible.

Staticnestedtypesserveasastructuringandscoping

mechanismforlogicallyrelatedtypes.However,staticnested

typesaremembersoftheirenclosingtypeandassuchcan

accessallothermembersoftheenclosingtypeincludingprivate

onesthroughanappropriateobjectreferenceofcourse.This

givesthenestedtypeaspecial,privilegedrelationshipwiththe

enclosingtype.

Becausestaticnestedtypesaremembersoftheirenclosing

type,thesameaccessibilityrulesapplytothemasforother

members.Forclassesthismeansthatastaticnestedclassor

interfacecanhaveprivate,package,protected,orpublicaccess,

whileforinterfaces,nestedtypesareimplicitlypublic.



5.1.1.StaticNestedClasses

Thestaticnestedclassisthesimplestformofnestedclass.You

declareonebyprecedingtheclassdeclarationwiththestatic

modifier.Whennestedinaninterface,aclassdeclarationis

alwaysstaticandthemodifieris,byconvention,omitted.A

staticnestedclassactsjustlikeanytop-levelclass.Itcan

extendanyotherclass(includingtheclassitisamemberof),[1]

implementanyinterfaceanditselfbeusedforfurtherextension

byanyclasstowhichitisaccessible.Itcanbedeclaredfinalor

abstract,justasatop-levelclasscan,anditcanhave



annotationsappliedtoit.

[1]Thisisaverycommonstructuringidiom.



Staticnestedclassesserveasamechanismfordefining

logicallyrelatedtypeswithinacontextinwhichthattypemakes

sense.Forexample,onpage62weshowedaPermissionsclass

thatbearsinformationaboutaBankAccountobject.Becausethe

PermissionsclassisrelatedtothecontractoftheBankAccount

classitishowaBankAccountobjectcommunicatesasetof

permissionsitisagoodcandidatetobeanestedclass:

publicclassBankAccount{

privatelongnumber;//accountnumber

privatelongbalance;//currentbalance(incents)

publicstaticclassPermissions{

publicbooleancanDeposit,

canWithdraw,

canClose;

}

//...

}



ThePermissionsclassisdefinedinsidetheBankAccountclass,

makingitamemberofthatclass.WhenpermissionsForreturnsa

Permissionsobject,itcanrefertotheclasssimplyasPermissionsin

thesamewayitcanrefertobalancewithoutqualification:

Permissionsisamemberoftheclass.Thefullnameoftheclassis

BankAccount.Permissions.Thisfullnameclearlyindicatesthatthe

classexistsaspartoftheBankAccountclass,notasastand-alone

type.CodeoutsidetheBankAccountclassmustusethefullname,

forexample:

BankAccount.Permissionsperm=acct.permissionsFor(owner);



IfBankAccountwereinapackagenamedbank,thefullnameofthe

classwouldbebank.BankAccount.Permissions(packagesare

discussedinChapter18).Inyourowncode,youcouldimport

theclassBankAccount.Permissionsandthenusethesimplename

Permissions,butyouwouldlosetheimportantinformationabout

thesubsidiarynatureoftheclass.

Staticnestedclassesaremembersoftheirenclosingtype.

Staticnestedclassesenclosedinaninterfaceareimplicitly

public;ifenclosedbyaclass,youcandeclarethemtobe

accessibleinanywayyoulike.Youcan,forexample,declarea

classthatisanimplementationdetailtobeprivate.Wedeclare

PermissionstobepublicbecauseprogrammersusingBankAccount

needtousetheclass.

SincePermissionsisamemberofBankAccount,thePermissionsclass

canaccessallothermembersofBankAccount,includingall

inheritedmembers.Forexample,ifPermissionsdeclareda

methodthattookaBankAccountobjectasanargument,that

methodwouldbeabletodirectlyaccessboththenumberand

balancefieldsofthataccount.Inthissensethenestedclassis

seenaspartoftheimplementationoftheenclosingclassandso

iscompletelytrusted.

Thereisnorestrictiononhowastaticnestedclasscanbe

extendeditcanbeextendedbyanyclasstowhichitis

accessible.Ofcourse,theextendedclassdoesnotinheritthe

privilegedaccessthatthenestedclasshastotheenclosing

class.

Nestedenumclassesarealwaysstatic,althoughbyconvention

thestaticmodifierisomittedfromtheenumdeclaration.Enum

classesaredescribedinChapter6.



5.1.2.NestedInterfaces



Nestedinterfacesarealsoalwaysstaticandagain,by

conventionthestaticmodifierisomittedfromtheinterface

declaration.Theyservesimplyasastructuringmechanismfor

relatedtypes.Whenwelookatnon-staticnestedclassesyou

willseethattheyareinherentlyconcernedwithimplementation

issues.Sinceinterfacesdonotdictateimplementationthey

cannotbenon-static.

Exercise5.1:ConsidertheAttrclassandAttributedinterface

fromChapter4.Shouldoneofthesebeanestedtypeofthe

other?Ifso,whichwaymakesthemostsense?



5.2.InnerClasses

Non-staticnestedclassesarecalledinnerclasses.Non-static

classmembersareassociatedwithinstancesofaclassnonstaticfieldsareinstancevariablesandnon-staticmethods

operateonaninstance.Similarly,aninnerclassisalso(usually)

associatedwithaninstanceofaclass,ormorespecificallyan

instanceofaninnerclassisassociatedwithaninstanceofits

enclosingclasstheenclosinginstanceorenclosingobject.

Youoftenneedtocloselytieanestedclassobjecttoa

particularobjectoftheenclosingclass.Consider,forexample,a

methodfortheBankAccountclassthatletsyouseethelastaction

performedontheaccount,suchasadepositorwithdrawal:

publicclassBankAccount{

privatelongnumber;//accountnumber

privatelongbalance;//currentbalance(incents)

privateActionlastAct;//lastactionperformed

publicclassAction{

privateStringact;

privatelongamount;

Action(Stringact,longamount){

this.act=act;

this.amount=amount;

}

publicStringtoString(){

//identifyourenclosingaccount

returnnumber+":"+act+""+amount;

}

}

publicvoiddeposit(longamount){

balance+=amount;

lastAct=newAction("deposit",amount);



}

publicvoidwithdraw(longamount){

balance-=amount;

lastAct=newAction("withdraw",amount);

}

//...

}



TheclassActionrecordsasingleactionontheaccount.Itisnot

declaredstatic,andthatmeansitsobjectsexistrelativetoan

objectoftheenclosingclass.

TherelationshipbetweenanActionobjectanditsBankAccount

objectisestablishedwhentheActionobjectiscreated,asshown

inthedepositandwithdrawmethods.Whenaninnerclassobject

iscreated,itmustbeassociatedwithanobjectofitsenclosing

class.Usually,innerclassobjectsarecreatedinsideinstance

methodsoftheenclosingclass,asindepositandwithdraw.When

thatoccursthecurrentobjectthisisassociatedwiththeinner

objectbydefault.Thecreationcodeindepositisthesameasthe

moreexplicit

lastAct=this.newAction("deposit",amount);



AnyBankAccountobjectcouldbesubstitutedforthis.Forexample,

supposeweaddatransferoperationthattakesaspecified

amountfromoneaccountandplacesitinthecurrent

accountsuchanactionneedstoupdatethelastActfieldofboth

accountobjects:

publicvoidtransfer(BankAccountother,longamount){

other.withdraw(amount);



deposit(amount);

lastAct=this.newAction("transfer",amount);

other.lastAct=other.newAction("transfer",amount);

}



InthiscasewebindthesecondActionobjecttothe

otherBankAccountobjectandstoreitasthelastactionoftheother

account.EachBankAccountobjectshouldonlyrefertoAction

objectsforwhichthatBankAccountobjectistheenclosing

instance.Itwouldmakenosenseabove,forexample,tostore

thesameActionobjectinboththecurrentlastActfieldand

other.lastAct.

Aninnerclassdeclarationisjustlikeatop-levelclass

declarationexceptforonerestrictioninnerclassescannothave

staticmembers(includingstaticnestedtypes),exceptforfinal

staticfieldsthatareinitializedtoconstantsorexpressionsbuilt

upfromconstants.Therationaleforallowingconstantstobe

declaredinaninnerclassisthesameasthatforallowingthem

ininterfacesitcanbeconvenienttodefineconstantswithinthe

typethatusesthem.

Aswithtop-levelclasses,innerclassescanextendanyother

classincludingitsenclosingclass[2]implementanyinterfaceand

beextendedbyanyotherclass.Aninnerclasscanbedeclared

finalorabstract,andcanhaveannotationsappliedtoit.

[2]Itishardtothinkofareasonwhyyouwouldwanttodothis,andeasytogetaheadachereasoningabout

whatitmeans.



Exercise5.2:CreateaversionofBankAccountthatrecordsthe

lasttenactionsontheaccount.Addahistorymethodthat

returnsaHistoryobjectthatwillreturnActionobjectsoneata

timeviaanextmethod,returningnullattheendofthelist.

ShouldHistorybeanestedclass?Ifso,shoulditbestaticor

not?



5.2.1.AccessingEnclosingObjects

ThetoStringmethodofActiondirectlyusesthenumberfieldofits

enclosingBankAccountobject.Anestedclasscanaccessall

membersofitsenclosingclassincludingprivatefieldsand

methodswithoutqualificationbecauseitispartoftheenclosing

class'simplementation.Aninnerclasscansimplynamethe

membersofitsenclosingobjecttousethem.Thenamesinthe

enclosingclassareallsaidtobeinscope.Theenclosingclass

canalsoaccesstheprivatemembersoftheinnerclass,butonly

byanexplicitreferencetoaninnerclassobjectsuchaslastAct.

Whileanobjectoftheinnerclassisalwaysassociatedwithan

objectoftheenclosingclass,theconverseisnottrue.Anobject

oftheenclosingclassneednothaveanyinnerclassobjects

associatedwithit,oritcouldhavemany.

WhendepositcreatesanActionobject,areferencetothe

enclosingBankAccountobjectisautomaticallystoredinthenew

Actionobject.Usingthissavedreference,theActionobjectcan

alwaysrefertotheenclosingBankAccountobject'snumberfieldby

thesimplenamenumber,asshownintoString.Thenameofthe

referencetotheenclosingobjectisthisprecededbythe

enclosingclassnameaformknownasqualified-this.For

example,toStringcouldreferencethenumberfieldoftheenclosing

BankAccountobjectexplicitly:

returnBankAccount.this.number+":"+act+""+amount;



Thequalified-thisreferencereinforcestheideathatthe

enclosingobjectandtheinnerobjectaretightlyboundaspart

ofthesameimplementationoftheenclosingclass.Thisis

furtherreinforcedbythequalified-superreference,whichallows

accesstomembersoftheenclosinginstance'ssuperclassthat

havebeenhidden,oroverridden,bytheenclosingclass.For



example,givenaclassTthatextendsS,withinTwecaninvoke

thesuperclassimplementationofamethodm,byusingsuper.m()

inanexpression.Similarly,inaninnerclassofT,wecaninvoke

thesameimplementationofmusingT.super.m()inanexpressiona

qualified-superreferenceandsimilarlyforfieldsofShiddenby

fieldsinT.

Anestedclasscanhaveitsownnestedclassesandinterfaces.

Referencestoenclosingobjectscanbeobtainedforanylevelof

nestinginthesameway:thenameoftheclassandthis.If

classXenclosesclassYwhichenclosesclassZ,codeinZcan

explicitlyaccessfieldsofXbyusingX.this.

Thelanguagedoesnotpreventyoufromdeeplynestingclasses,

butgoodtasteshould.AdoublynestedclasssuchasZhas

threenamescopes:itself,itsimmediateenclosingclassY,and

outermostclassX.SomeonereadingthecodeforZmust

understandeachclassthoroughlytoknowinwhichcontextan

identifierisboundandwhichenclosingobjectwasboundto

whichnestedobject.Werecommendnestingonlyonelevel

undermostcircumstances.Nestingmorethantwolevelsinvites

areadabilitydisasterandshouldprobablyneverbeattempted.



5.2.2.ExtendingInnerClasses

Aninnerclasscanbeextendedjustasanystaticnestedclass

ortop-levelclasscan.Theonlyrequirementisthatobjectsof

theextendedclassmuststillbeassociatedwithobjectsofthe

originalenclosingclassorasubclass.Usuallythisisnota

problembecausetheextendedinnerclassisoftendeclared

withinanextensionoftheouterclass:

classOuter{

classInner{}

}



classExtendedOuterextendsOuter{

classExtendedInnerextendsInner{}

Innerref=newExtendedInner();

}



ThereffieldisinitializedwhenanExtendedOuterobjectiscreated.

ThecreationoftheExtendedInnerinstanceusesthedefaultno-arg

constructorofExtendedInner,whichinturnimplicitlyinvokesthe

defaultno-argconstructorofInnerbyusingsuper.The

constructorforInnerrequiresanobjectofOutertobindto,which

inthiscaseisimplicitlythecurrentobjectofExtendedOuter.

Iftheenclosingclassoftheinnersubclassisnotasubclassof

Outer,oriftheinnersubclassisnotitselfaninnerclass,thenan

explicitreferencetoanobjectofOutermustbesuppliedwhen

theInnerconstructorisinvokedviasuper.Forexample:

classUnrelatedextendsOuter.Inner{

Unrelated(Outerref){

ref.super();

}

}



WhentheconstructionofanUnrelatedobjectreachesthepoint

wherethesuperclassconstructorisinvoked,theremustbean

objectofclassOutertowhichthesuperclassobjectcanbe

bound.SinceUnrelatedisnotitselfaninnerclassofOuter,there

isnoimplicitenclosingobject.Similarly,becauseUnrelatedisnot

asubclassofOuter,thecurrentobjectofUnrelatedisnotavalid

enclosingobject.Wemustprovideanexplicitreferencetoan

Outerobjectforthesuperclassobjecttobindto.Wechoseto

supplythatreferenceusinganargumenttotheUnrelated

constructor,whichusesitasanexplicitbindingreferenceinthe



invocationofthesuperclassconstructor.

Notethatyoucannotusetheinnerclasscreationsyntaxto

externallyprovideanOuterobject,asin

Outerref=newOuter();

Unrelatedu=ref.newUnrelated();//INVALID



becausethissyntaxsuppliesanenclosingobjectforthe

UnrelatedclassandUnrelatedisnotaninnerclass.

Aninnerclasscanextendanother,unrelated,innerclass

providedanappropriateenclosinginstanceissuppliedtothe

superclass,asjustdescribed.Theresultinginnerclassthenhas

twoenclosinginstancesonefortheextendedclassandonefor

thesuperclass.Suchdesignsareconvoluted,however,andare

bestavoided.



5.2.3.Inheritance,Scoping,andHiding

Withinaninnerclass,allnamesdeclaredwithintheenclosing

classaresaidtobeinscopetheycanbeusedasiftheinner

classcodeweredeclaredintheouterclass.Aninnerclass'sown

fieldsandmethods(andnestedtypes)canhidethoseofthe

enclosingobject.Therearetwowaysinwhichthiscanoccur:

afieldormethodisdeclaredintheinnerclass

afieldormethodisinheritedbytheinnerclass

Inbothcasesanyuseofthesimplenamereferstothemember

oftheinnerclass,whetherdeclaredorinherited.Theenclosing

object'sfieldormethodmustbeaccessedexplicitlyusinga



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Chapter 5. Nested Classes and Interfaces

Tải bản đầy đủ ngay(0 tr)

×