„Java“ palaiko klasės pakartotinį naudojimą paveldėjimo ir sudėties būdu. Ši dviejų dalių mokymo programa išmokys jus naudoti paveldėjimą savo „Java“ programose. 1 dalyje sužinosite, kaip naudoti tęsiasi
raktinį žodį, kad gautumėte vaikų klasę iš tėvų klasės, pasikvieskite tėvų klasės konstruktorius ir metodus bei ignoruosite metodus. 2 dalyje apžiūrėsite java.lang.Object
, kuris yra „Java“ superklasė, iš kurios paveldi visos kitos klasės.
Norėdami baigti mokymąsi apie paveldėjimą, būtinai peržiūrėkite mano „Java“ patarimą, kuriame paaiškinta, kada naudoti kompoziciją ir paveldėjimą. Sužinosite, kodėl kompozicija yra svarbus paveldėjimo papildymas ir kaip ją naudoti, kad apsisaugotumėte nuo problemų, susijusių su jūsų Java programų inkapsuliacija.
atsisiųsti Gauti kodą Atsisiųskite šaltinį, pvz., programas, šioje pamokoje. Sukūrė Jeffas Friesenas, skirtas „JavaWorld“.Java paveldėjimas: du pavyzdžiai
Paveldėjimas yra programavimo konstrukcija, kurią sukuria programinės įrangos kūrėjai yra-santykiai tarp kategorijų. Paveldėjimas leidžia mums išgauti konkretesnes kategorijas iš bendresnių. Konkrečiau kategorija yra tam tikros rūšies generiškesnė kategorija. Pavyzdžiui, atsiskaitomoji sąskaita yra tam tikra sąskaita, kurioje galite atlikti indėlius ir išsigryninti. Panašiai sunkvežimis yra tam tikra transporto priemonė, naudojama gabenti didelius daiktus.
Paveldėjimas gali nusileisti keliais lygmenimis, o tai lemia vis specifines kategorijas. Pavyzdžiui, 1 paveiksle parodytas automobilio ir sunkvežimio paveldėjimas iš transporto priemonės; universalas, paveldimas iš automobilio; ir šiukšliavežis, paveldėtas iš sunkvežimio. Rodyklės nurodo iš konkretesnių „vaikų“ kategorijų (žemyn žemyn) į mažiau specifines „tėvų“ kategorijas (aukštesnės).

Šis pavyzdys iliustruoja vienas paveldėjimas kurioje vaiko kategorija paveldi būseną ir elgesį iš vienos tiesioginių tėvų kategorijos. Priešingai, daugkartinis paveldėjimas leidžia vaiko kategorijai paveldėti būseną ir elgesį iš dviejų ar daugiau tiesioginių tėvų kategorijų. 2 paveiksle esanti hierarchija iliustruoja daugybinį paveldėjimą.

Kategorijos apibūdinamos pagal klases. „Java“ palaiko vieną paveldėjimą klasės pratęsimas, kurioje viena klasė tiesiogiai paveldi prieinamus laukus ir metodus iš kitos klasės, pratęsdama tą klasę. Vis dėlto „Java“ nepalaiko kelių paveldėjimų per klasės pratęsimą.
Peržiūrėdami paveldėjimo hierarchiją, galite lengvai aptikti kelis paveldėjimus pagal deimantų modelį. 2 paveiksle pavaizduotas šis modelis transporto priemonės, sausumos transporto priemonės, vandens transporto priemonės ir orlaivio kontekste.
Praplečiamas raktinis žodis
„Java“ palaiko klasės pratęsimą per tęsiasi
raktinis žodis. Kai yra, tęsiasi
nurodo tėvų ir vaikų santykius tarp dviejų klasių. Žemiau aš naudoju tęsiasi
užmegzti santykį tarp klasių Transporto priemonė
ir Automobilis
ir tada tarp Sąskaita
ir Taupomoji sąskaita
:
Sąrašas 1. The tęsiasi
raktinis žodis nurodo tėvų ir vaikų santykius
klasė Transporto priemonė {// narių deklaracijos} klasė Automobilis pratęsia transporto priemonę {// paveldi prieinamus narius iš Transporto priemonės // pateik savo narių deklaracijas} klasė Sąskaita {// narių deklaracijos} klasė Taupomoji sąskaita pratęsia sąskaitą {// paveldi prieinamus narius iš paskyros // pateikti savo narių deklaracijos}
tęsiasi
raktinis žodis nurodomas po klasės pavadinimo ir prieš kitą klasės pavadinimą. Klasės pavadinimas anksčiau tęsiasi
identifikuoja vaiką ir klasės pavadinimą po tęsiasi
identifikuoja tėvą. Po to neįmanoma nurodyti kelių klasių pavadinimų tęsiasi
nes „Java“ nepalaiko daugelio klasių paveldėjimo.
Šie pavyzdžiai užkoduoja ryšius: Automobilis
yra specializuota Transporto priemonė
ir Taupomoji sąskaita
yra specializuota Sąskaita
. Transporto priemonė
ir Sąskaita
yra žinomi kaip bazinės klasės, tėvų klasėsarba superklasės. Automobilis
ir Taupomoji sąskaita
yra žinomi kaip išvestinės klasės, vaikų klasėsarba poklasiai.
Baigiamosios klasės
Galite paskelbti klasę, kurios nereikėtų pratęsti; pavyzdžiui, saugumo sumetimais. „Java“ mes naudojame galutinis
raktinį žodį, kad būtų išvengta kai kurių klasių pratęsimo. Paprasčiausiai pridėkite klasės antraštę galutinis
, kaip ir paskutinės klasės slaptažodis
. Atsižvelgdamas į šią deklaraciją, kompiliatorius praneš apie klaidą, jei kas nors bandys išplėsti Slaptažodis
.
Vaikų klasės paveldimus laukus ir metodus paveldi iš savo tėvų klasių ir kitų protėvių. Tačiau jie niekada nepaveldi konstruktorių. Vietoj to, vaikų klasės deklaruoja savo konstruktorius. Be to, jie gali deklaruoti savo sritis ir metodus, kaip juos atskirti nuo tėvų. Apsvarstykite 2 sąrašą.
2. sąrašas Sąskaita
tėvų klasė
klasės sąskaita {private String name; privati ilga suma; Sąskaita (eilutės pavadinimas, ilga suma) {this.name = vardas; setAmount (suma); } negaliojantis indėlis (ilga suma) {this.suma + = suma; } String getName () {grąžinimo vardas; } long getAmount () {grąžinimo suma; } void setAmount (ilga suma) {this.suma = suma; }}
2 sąraše aprašoma bendroji banko sąskaitos klasė, turinti pavadinimą ir pradinę sumą, kurios abi nustatytos konstruktoriuje. Be to, tai leidžia vartotojams atlikti indėlius. (Galite išsigryninti įnešdami neigiamas pinigų sumas, bet mes nepaisysime šios galimybės.) Atminkite, kad sąskaitos pavadinimas turi būti nustatytas sukūrus sąskaitą.
Reprezentuojančios valiutos vertės
centų skaičius. Galbūt norėtumėte naudoti a dvigubai
arba a plūdė
saugoti pinigines vertes, tačiau tai gali sukelti netikslumų. Norėdami apsvarstyti geresnį sprendimą, apsvarstykite Didelis dešimtainis
, kuri yra „Java“ standartinės klasės bibliotekos dalis.
3 sąraše pateikiami a Taupomoji sąskaita
vaikų klasė, kuri pratęsia savo Sąskaita
tėvų klasė.
Sąrašas 3. A Taupomoji sąskaita
vaikų klasė pratęsia savo Sąskaita
tėvų klasė
klasė Taupomoji sąskaita pratęsia Sąskaitą {Taupomoji sąskaita (ilga suma) {super ("taupymas", suma); }}
Taupomoji sąskaita
klasė yra nereikšminga, nes jai nereikia deklaruoti papildomų laukų ar metodų. Tačiau jis paskelbia konstruktorių, kuris inicijuoja jo laukus Sąskaita
superklasė. Inicijavimas įvyksta, kai Sąskaita
konstruktorius vadinamas Java super
raktinis žodis, po kurio pateikiamas skliaustuose pateiktas argumentų sąrašas.
Kada ir kur skambinti super ()
Lygiai taip tai ()
turi būti pirmasis konstruktoriaus elementas, iškviečiantis kitą tos pačios klasės konstruktorių, super ()
turi būti pirmasis konstruktoriaus elementas, kuris iškviečia konstruktorių savo superklase. Jei pažeisite šią taisyklę, kompiliatorius praneš apie klaidą. Kompiliatorius taip pat praneš apie klaidą, jei aptiks a super ()
iškviesti metodą; tik kada skambinti super ()
konstruktoriuje.
4 sąrašas dar tęsiasi Sąskaita
su „CheckingAccount“
klasė.
Sąrašas 4. A „CheckingAccount“
vaikų klasė pratęsia savo Sąskaita
tėvų klasė
klasė „CheckingAccount“ pratęsia sąskaitą {CheckingAccount (ilga suma) {super ("tikrinimas", suma); } negaliojantis atsiimti (ilga suma) {setAmount (getAmount () - suma); }}
„CheckingAccount“
yra šiek tiek reikšmingesnis nei Taupomoji sąskaita
nes deklaruoja a atsiimti ()
metodas. Atkreipkite dėmesį į šio metodo raginimus setAmount ()
ir getAmount ()
, kuris „CheckingAccount“
paveldi iš Sąskaita
. Negalite tiesiogiai pasiekti suma
laukas Sąskaita
nes šis laukas yra deklaruotas privatus
(žr. 2 sąrašą).
super () ir be argumentų konstruktorius
Jei super ()
nėra nurodytas poklasio konstruktoriuje, o jei superklasė nedeklaruoja a be argumentų
konstruktorius, tada kompiliatorius praneš apie klaidą. Taip yra todėl, kad poklasio konstruktorius turi paskambinti a be argumentų
superklasės konstruktorius, kai super ()
nėra.
Klasių hierarchijos pavyzdys
Aš sukūriau „AccountDemo“
programos klasė, leidžianti išbandyti Sąskaita
klasės hierarchija. Pirmiausia pažvelk į „AccountDemo“
šaltinio kodas.
5 sąrašas. „AccountDemo“
parodo sąskaitų klasės hierarchiją
class AccountDemo {public static void main (String [] args) {Taupomoji sąskaita sa = nauja Taupomoji sąskaita (10000); System.out.println ("paskyros pavadinimas:" + sa.getName ()); System.out.println ("pradinė suma:" + sa.getAmount ()); sa.depositas (5000); System.out.println ("nauja suma po indėlio:" + sa.getAmount ()); „CheckingAccount ca“ = nauja „CheckingAccount“ (20000); System.out.println ("paskyros pavadinimas:" + ca.getName ()); System.out.println ("pradinė suma:" + ca.getAmount ()); maždaug indėlis (6000); System.out.println ("nauja suma po indėlio:" + ca.getAmount ()); maždaug atsiimti (3000); System.out.println ("nauja suma po atsiėmimo:" + ca.getAmount ()); }}
pagrindinis ()
metodas 5 sąraše pirmiausia parodo Taupomoji sąskaita
tada „CheckingAccount“
. Darant prielaidą Account.java
, Taupomoji sąskaita.java
, CheckingAccount.java
ir AccountDemo.java
šaltinio failai yra tame pačiame kataloge, atlikite bet kurią iš šių komandų, kad sukompiluotumėte visus šiuos šaltinio failus:
javac AccountDemo.java javac * .java
Norėdami paleisti programą, vykdykite šią komandą:
„java AccountDemo“
Turėtumėte stebėti šį rezultatą:
sąskaitos pavadinimas: taupymo pradinė suma: 10000 nauja suma po indėlio: 15000 sąskaitos pavadinimas: tikrinant pradinę sumą: 20000 nauja suma po indėlio: 26000 nauja suma po atsiėmimo: 23000
Metodo viršijimas (ir metodo perkrova)
Poklasis gali nepaisyti (pakeisti) paveldėtą metodą, kad vietoj jo būtų iškviesta poklasio versija. Nepaisomas metodas turi nurodyti tą patį pavadinimą, parametrų sąrašą ir grąžinimo tipą, kaip ir metodas, kurio nepaisoma. Norėdamas parodyti, aš paskelbiau a spausdinti ()
metodas Transporto priemonė
klasė žemiau.
Sąrašas 6. Deklaravimas a spausdinti ()
metodas turi būti nepaisomas
klasės transporto priemonė {privati styginių markė; privati styginių modelis; privatus int metai; Transporto priemonė (styginių markė, styginių modelis, metų metai) {this.make = markė; tai.modelis = modelis; tai.metai = metai; } String getMake () {return make; } String getModel () {grąžinimo modelis; } int getYear () {grąžinimo metai; } void print () {System.out.println ("Gamintojas:" + padarykite + ", Modelis:" + modelis + ", Metai:" + metai); }}
Toliau aš nepaisau spausdinti ()
viduje konors Sunkvežimis
klasė.
Sąrašas 7. Nepaisoma spausdinti ()
a Sunkvežimis
poklasis
klasės sunkvežimis prailgina transporto priemonę {privatus dvigubas tonažas; Sunkvežimis (styginių markė, styginių modelis, tarptautiniai metai, dvigubas tonažas) {super (markė, modelis, metai); this.tonnage = tonažas; } double getTonnage () {grąžinimo tonažas; } void print () {super.print (); System.out.println ("Tonažas:" + tonažas); }}
Sunkvežimis
's spausdinti ()
metodas turi tą patį pavadinimą, grąžinimo tipą ir parametrų sąrašą kaip Transporto priemonė
's spausdinti ()
metodas. Atkreipkite dėmesį ir į tai Sunkvežimis
's spausdinti ()
metodas pirmiausia skambina Transporto priemonė
's spausdinti ()
metodas priešdėliais super.
prie metodo pavadinimo. Dažnai yra gera idėja pirmiausia įvykdyti superklasės logiką, o paskui - poklasio logiką.
Supaklasės metodų iškvietimas iš poklasio metodų
Norėdami iškviesti superklasės metodą iš svarbesnio poklasio metodo, prieš metodo pavadinimą įrašykite rezervuotą žodį super
ir nario prieigos operatorius. Priešingu atveju jūs rekursyviai iškviesite poklasio svarbesnįjį metodą. Kai kuriais atvejais poklasis užmaskuos neprivatus
superklasės laukų, deklaruodami to paties pavadinimo laukus. Tu gali naudoti super
nariams ir prieigos nariams prieigai prie neprivatus
superklasės laukai.
Norėdami užbaigti šį pavyzdį, ištraukiau a „VehicleDemo“
klasės pagrindinis ()
metodas:
Sunkvežimis = naujas sunkvežimis („Ford“, „F150“, 2008, 0,5); System.out.println ("Make =" + truck.getMake ()); System.out.println ("Model =" + truck.getModel ()); System.out.println ("Metai =" + sunkvežimis.getYear ()); System.out.println ("Tonnage =" + sunkvežimis.getTonnage ()); sunkvežimis.spauda ();
Paskutinė eilutė sunkvežimis.spauda ();
, skambučiai sunkvežimis
's spausdinti ()
metodas. Šis metodas pirmiausia skambina Transporto priemonė
's spausdinti ()
pateikti sunkvežimio markę, modelį ir metus; tada jis pateikia sunkvežimio tonažą. Ši išvesties dalis parodyta žemiau:
Markė: Ford, Modelis: F150, Metai: 2008 Tonažas: 0.5
Norėdami užblokuoti metodo nepaisymą, naudokite final
Kartais dėl saugumo ar kitų priežasčių gali tekti deklaruoti metodą, kurio nereikėtų nepaisyti. Galite naudoti galutinis
raktinis žodis šiam tikslui. Norėdami išvengti nepaisymo, paprasčiausiai prieš metodo antraštę įrašykite galutinis
, kaip ir paskutinė eilutė „getMake“ ()
. Tada kompiliatorius praneš apie klaidą, jei kas nors bandys nepaisyti šio metodo poklasyje.
Metodo perkrova ir nepaisoma
Tarkime, kad pakeitėte spausdinti ()
metodas 7 sąraše su vienu iš toliau pateiktų būdų:
void print (eilutės savininkas) {System.out.print ("Savininkas:" + savininkas); super.spaudas (); }
Modifikuotas Sunkvežimis
klasėje dabar yra du spausdinti ()
metodai: prieš tai aiškiai deklaruotas metodas ir iš jo paveldėtas metodas Transporto priemonė
. negaliojantis spausdinimas (eilutės savininkas)
metodas nepaiso Transporto priemonė
's spausdinti ()
metodas. Vietoj to perkrovos tai.
Bandymą perkrauti, užuot nepaisius metodo kompiliavimo metu, galite aptikti priešklasei metodo antraštę pridėdami @ Nepaisyti
anotacija:
@ Nepaisyti negaliojančio spausdinimo (eilutės savininkas) {System.out.print ("Savininkas:" + savininkas); super.spaudas (); }
Nurodant @ Nepaisyti
kompiliatoriui sako, kad nurodytas metodas nepaiso kito metodo. Jei kas nors bandė perkrauti metodą, kompiliatorius praneša apie klaidą. Be šios anotacijos kompiliatorius nepraneša apie klaidą, nes metodo perkrovimas yra teisėtas.
Kada naudoti „@Override“
Išsiugdykite įprotį prefiksuoti svarbiausius metodus @ Nepaisyti
. Šis įprotis padės daug greičiau aptikti perkrovos klaidas.