Java podpira ponovno uporabo razreda z dedovanjem in sestavljanjem. Ta dvodelna vadnica vas uči, kako uporabljati dedovanje v svojih programih Java. V prvem delu boste izvedeli, kako uporabljati podaljša
ključna beseda za izpeljavo podrejenega razreda iz nadrejenega razreda, priklic konstruktorjev in metod nadrejenega razreda in preglasitev metod. V 2. delu boste obiskali java.lang.Object
, ki je Javin nadrazred, iz katerega podeduje vsak drugi razred.
Če želite dokončati učenje o dedovanju, si oglejte moj namig Java, ki pojasnjuje, kdaj uporabiti sestavo in dedovanje. Izvedeli boste, zakaj je sestava pomemben dodatek dedovanju in kako jo uporabljati za zaščito pred težavami z enkapsulacijo v vaših programih Java.
prenos Prenesite kodo Prenesite izvorno kodo, na primer programe v tej vadnici. Ustvaril Jeff Friesen za JavaWorld.Dedovanje Java: Dva primera
Dedovanje je programska konstrukcija, ki jo uporabljajo razvijalci programske opreme je-a odnosi med kategorijami. Dedovanje nam omogoča, da iz bolj splošnih izpeljemo bolj specifične kategorije. Bolj specifična kategorija je bolj splošne kategorije. Na primer, tekoči račun je nekakšen račun, na katerem lahko opravite pologe in dvige. Podobno je tovornjak vrsta vozila, ki se uporablja za vleko večjih predmetov.
Dedovanje se lahko spusti skozi več ravni, kar vodi do vedno bolj specifičnih kategorij. Kot primer je na sliki 1 prikazan podedovanje avtomobila in tovornjaka od vozila; karavan, ki podeduje iz avtomobila; in smetarsko vozilo, ki ga podeduje od tovornjaka. Puščice kažejo od bolj specifičnih "podrejenih" kategorij (spodaj navzdol) do manj specifičnih "nadrejenih" kategorij (višje navzgor).

Ta primer ponazarja samostojna dediščina v katerem podrejena kategorija podeduje stanje in vedenja iz ene neposredne nadrejene kategorije. V nasprotju, večkratno dedovanje omogoča podrejeni kategoriji podedovati stanje in vedenje iz dveh ali več neposrednih starševskih kategorij. Hierarhija na sliki 2 prikazuje večkratno dedovanje.

Kategorije so opisane po razredih. Java podpira enojno dedovanje prek podaljšek razreda, v katerem en razred neposredno podeduje dostopna polja in metode drugega razreda z razširitvijo tega razreda. Java pa ne podpira večkratnega dedovanja prek razširitve razreda.
Ko si ogledujete hierarhijo dedovanja, lahko večkratno dedovanje enostavno zaznate s prisotnostjo diamantnega vzorca. Slika 2 prikazuje ta vzorec v kontekstu vozila, kopenskega vozila, vodnega vozila in lebdenja.
Ključna beseda extends
Java podpira razširitev razreda prek podaljša
ključna beseda. Ko je prisoten, podaljša
določa razmerje med staršem in otrokom med dvema razredoma. Spodaj uporabljam podaljša
vzpostaviti odnos med razredi Vozilo
in Avto
in nato med račun
in Varčevalni račun
:
Seznam 1. podaljša
ključna beseda določa razmerje med staršem in otrokom
class Vehicle {// izjave članov} class Car razširja Vehicle {// podeduje dostopne člane iz Vehicle // zagotavlja lastne izjave članov} class Account {// izjave članov} class SavingsAccount podaljša račun {// podeduje dostopne člane iz Account // zagotavlja izjave lastnih članov}
The podaljša
ključna beseda je navedena za imenom razreda in pred imenom drugega razreda. Ime razreda prej podaljša
identificira otroka in ime razreda po podaljša
identificira starša. Po tem ni mogoče določiti več imen razredov podaljša
ker Java ne podpira večkratnega dedovanja na osnovi razredov.
Ti primeri kodificirajo razmerja is-a: Avto
je specializirano Vozilo
in Varčevalni račun
je specializirano račun
. Vozilo
in račun
so znani kot osnovni razredi, razredi staršev, ali superrazredi. Avto
in Varčevalni račun
so znani kot izpeljani razredi, otroški razredi, ali podrazredi.
Zaključni pouk
Lahko razglasite razred, ki ga ne bi smeli razširiti; na primer iz varnostnih razlogov. V Javi uporabljamo dokončno
ključno besedo, da preprečite razširitev nekaterih razredov. Preprosto pred glavo glave preda dodajte dokončno
, kot v geslo končnega razreda
. Glede na to izjavo bo prevajalnik sporočil napako, če bo nekdo poskusil razširiti Geslo
.
Otroški razredi podedujejo dostopna polja in metode od svojih starševskih razredov in drugih prednikov. Nikoli ne podedujejo konstruktorjev. Namesto tega otroški razredi razglasijo svoje konstruktorje. Poleg tega lahko prijavijo svoja polja in metode, s katerimi jih ločijo od staršev. Razmislite o seznamu 2.
Seznam 2. An račun
razred staršev
razred Račun {ime zasebnega niza; zasebni dolg znesek; Račun (ime niza, dolg znesek) {this.name = ime; setAmount (znesek); } neveljavna vloga (dolg znesek) {this.amount + = znesek; } String getName () {return ime; } long getAmount () {vrnjeni znesek; } void setAmount (dolg znesek) {this.amount = znesek; }}
Seznam 2 opisuje generični razred bančnega računa, ki ima ime in začetni znesek, ki sta oba nastavljena v konstruktorju. Uporabnikom omogoča tudi polog. (Izplačila lahko izvedete tako, da položite negativne zneske denarja, vendar bomo to možnost prezrli.) Upoštevajte, da je treba ob ustvarjanju računa nastaviti ime računa.
Predstavljanje valutnih vrednosti
štetje penijev. Morda raje uporabite dvojno
ali a plovec
za shranjevanje denarnih vrednosti, vendar to lahko privede do netočnosti. Za boljšo rešitev razmislite BigDecimal
, ki je del standardne knjižnice razredov Java.
Seznam 3 predstavlja a Varčevalni račun
otroški razred, ki razširja svoj račun
razred staršev.
Seznam 3. A Varčevalni račun
otroški razred podaljša svoj račun
razred staršev
razred SavingsAccount razširja račun {SavingsAccount (dolg znesek) {super ("prihranek", znesek); }}
The Varčevalni račun
razred je nepomemben, ker mu ni treba prijaviti dodatnih polj ali metod. Deklarira pa konstruktor, ki inicializira polja v njem račun
superrazred. Inicializacija se zgodi, ko račun
Konstruktor se pokliče prek Jave super
ključni besedi, ki ji sledi seznam argumentov v oklepaju.
Kdaj in kje poklicati super ()
Tako kot to ()
mora biti prvi element v konstruktorju, ki pokliče drugi konstruktor v istem razredu, super ()
mora biti prvi element v konstruktorju, ki pokliče konstruktor v svojem superrazredu. Če kršite to pravilo, bo prevajalnik sporočil napako. Prevajalnik bo sporočil tudi napako, če zazna a super ()
priklic metode; samo kdaj super ()
v konstruktorju.
Seznam 4 se še razširja račun
z Preverjanje računa
razred.
Seznam 4. A Preverjanje računa
otroški razred podaljša svoj račun
razred staršev
razred CheckingAccount podaljša račun {CheckingAccount (dolg znesek) {super ("preverjanje", znesek); } neveljaven umik (dolg znesek) {setAmount (getAmount () - znesek); }}
Preverjanje računa
je malo bolj bistven kot Varčevalni račun
ker razglaša a dvigniti()
metoda. Upoštevajte klice te metode setAmount ()
in getAmount ()
, ki Preverjanje računa
podeduje od račun
. Ne morete neposredno dostopati do znesek
polje v račun
ker je to polje prijavljeno zasebno
(glej seznam 2).
super () in konstruktor brez argumentov
Če super ()
ni določen v konstruktorju podrazreda in če nadrazred ne deklarira brez argumenta
konstruktor, bo prevajalnik sporočil napako. To je zato, ker mora konstruktor podrazreda poklicati a brez argumenta
konstruktor superklase, ko super ()
ni prisoten.
Primer hierarhije razredov
Ustvaril sem AccountDemo
razred, ki vam omogoča, da preizkusite račun
razredna hierarhija. Najprej si oglejte AccountDemo
izvorna koda.
Seznam 5. AccountDemo
prikazuje hierarhijo razreda računov
class AccountDemo {public static void main (String [] args) {SavingsAccount sa = nov SavingsAccount (10000); System.out.println ("ime računa:" + sa.getName ()); System.out.println ("začetni znesek:" + sa.getAmount ()); sa.depozit (5000); System.out.println ("nov znesek po vplačilu:" + sa.getAmount ()); CheckingAccount ca = nov CheckingAccount (20000); System.out.println ("ime računa:" + ca.getName ()); System.out.println ("začetni znesek:" + ca.getAmount ()); približno depozit (6000); System.out.println ("nov znesek po vplačilu:" + ca.getAmount ()); približno umik (3000); System.out.println ("nov znesek po dvigu:" + ca.getAmount ()); }}
The glavni ()
metoda iz seznama 5 najprej prikaže Varčevalni račun
, potem Preverjanje računa
. Ob predpostavki Account.java
, SavingsAccount.java
, CheckingAccount.java
, in AccountDemo.java
izvorne datoteke so v istem imeniku, za prevajanje vseh teh izvornih datotek izvedite enega od naslednjih ukazov:
javac AccountDemo.java javac * .java
Za zagon aplikacije izvedite naslednji ukaz:
java AccountDemo
Upoštevati morate naslednje rezultate:
ime računa: začetni znesek prihranka: 10000 nov znesek po vplačilu: 15000 ime računa: preverjanje začetnega zneska: 20000 nov znesek po vplačilu: 26000 nov znesek po dvigu: 23000
Preglasitev metode (in preobremenitev metode)
Podrazred lahko preglasiti (zamenjati) podedovano metodo, tako da se namesto nje pokliče različica metode podrazreda. Preglasitvena metoda mora navesti isto ime, seznam parametrov in vrsto vrnitve kot metoda, ki jo preglasite. Za dokaz sem razglasil natisni ()
metoda v Vozilo
razred spodaj.
Seznam 6. Prijava a natisni ()
metoda, ki jo je treba preglasiti
razred Vozilo {private String make; model zasebnega niza; zasebno int leto; Vozilo (znamka niza, model niza, int leto) {this.make = znamka; this.model = model; this.year = leto; } String getMake () {return make; } String getModel () {return model; } int getYear () {vrnjeno leto; } void print () {System.out.println ("Make:" + make + ", Model:" + model + ", Leto:" + leto); }}
Nato preglasim natisni ()
v Tovornjak
razred.
Seznam 7. Preglasitev natisni ()
v Tovornjak
podrazred
razred Truck podaljša vozilo {zasebna dvojna tonaža; Tovornjak (znamka niza, model niza, int leto, dvojna tonaža) {super (znamka, model, leto); this.tonnage = tonaža; } double getTonnage () {povratna tonaža; } void print () {super.print (); System.out.println ("Tonaža:" + tonaža); }}
Tovornjak
je natisni ()
metoda ima enako ime, vrsto vrnitve in seznam parametrov kot Vozilo
je natisni ()
metoda. Upoštevajte tudi to Tovornjak
je natisni ()
metoda najprej pokliče Vozilo
je natisni ()
metoda s predpono super
do imena metode. Pogosto je dobro najprej izvršiti logiko superrazreda, nato pa logiko podrazreda.
Klicanje metod superrazreda iz metod podrazredov
Če želite iz nadrejene metode priklicati metodo superklase, pred metodo predpona dodajte rezervirano besedo super
in operaterja dostopa do člana. V nasprotnem primeru boste na koncu rekurzivno poklicali nadrejeno metodo podrazreda. V nekaterih primerih bo podrazred prikrilzasebno
polja superrazreda z razglasitvijo istoimenskih polj. Lahko uporabiš super
in operaterja dostopa za dostop dozasebno
polja superrazreda.
Za dopolnitev tega primera sem izvlekel a VehicleDemo
razredov glavni ()
metoda:
Tovornjak tovornjak = nov tovornjak ("Ford", "F150", 2008, 0,5); System.out.println ("Make =" + truck.getMake ()); System.out.println ("Model =" + truck.getModel ()); System.out.println ("Leto =" + truck.getYear ()); System.out.println ("Tonaža =" + truck.getTonnage ()); truck.print ();
Zadnja vrstica, truck.print ();
, klici tovornjak
je natisni ()
metoda. Ta metoda najprej pokliče Vozilo
je natisni ()
za prikaz znamke, modela in leta tovornjaka; nato odda tonažo tovornjaka. Ta del rezultata je prikazan spodaj:
Znamka: Ford, Model: F150, Leto: 2008 Tonaža: 0,5
Uporabite final, da blokirate preglasitev metode
Občasno boste morda morali prijaviti metodo, ki je zaradi varnosti ali drugega razloga ne bi smeli preglasiti. Lahko uporabite dokončno
ključna beseda za ta namen. Če želite preprečiti razveljavitev, preprosto pred glavo glave metode dodajte dokončno
, kot v končni niz getMake ()
. Prevajalnik bo nato sporočil napako, če bo kdo poskušal to metodo preglasiti v podrazredu.
Preobremenitev metode v primerjavi s preglasitvijo
Recimo, da ste zamenjali natisni ()
v seznamu 7 s spodnjim:
void print (Lastnik niza) {System.out.print ("Owner:" + owner); super.print (); }
Spremenjeno Tovornjak
razred ima zdaj dva natisni ()
metode: prejšnja izrecno deklarirana metoda in metoda, podedovana od Vozilo
. The void print (lastnik niza)
metoda ne preglasi Vozilo
je natisni ()
metoda. Namesto tega preobremenitve to.
Poskus preobremenitve lahko zaznate, namesto da bi preglasili metodo v času prevajanja, tako da pred glavo glave metode podrazreda dodate @Override
opomba:
@Override void print (Lastnik niza) {System.out.print ("Lastnik:" + lastnik); super.print (); }
Določanje @Override
pove prevajalniku, da podana metoda preglasi drugo metodo. Če bi nekdo poskušal metodo preobremeniti, bi prevajalnik sporočil napako. Brez tega pripisa prevajalnik ne bi poročal o napaki, ker je preobremenitev metode zakonita.
Kdaj uporabiti @Override
Razvijte navado predpiševanja nadrejenih metod pred @Override
. Ta navada vam bo veliko prej pomagala odkriti napake pri preobremenitvi.