Ohjelmointi

Perintö Javaissa, osa 1: Laajentaa avainsanaa

Java tukee luokan uudelleenkäyttöä perimisen ja sommittelun kautta. Tämä kaksiosainen opetusohjelma opettaa sinulle, miten perintöä käytetään Java-ohjelmissa. Osassa 1 opit käyttämään ulottuu avainsana johtaa lapsiluokka vanhempien luokasta, käyttää vanhempien luokan rakentajia ja menetelmiä sekä ohittaa menetelmiä. Osassa 2 kiertue java.lang.objekti, joka on Javan superluokka, josta kaikki muut luokat perivät.

Viimeistele oppimisesi perinnöstä tarkistamalla Java-vinkkini, jossa selitetään, milloin koostumusta ja perintöä käytetään. Opit, miksi sommittelu on tärkeä lisäys perintöön, ja kuinka sitä käytetään suojaamaan Java-ohjelmiesi kapselointiin liittyviltä ongelmilta.

lataa Hanki koodi Lataa lähdekoodi esimerkiksi sovelluksiin tässä opetusohjelmassa. Luonut Jeff Friesen JavaWorldille.

Java-perintö: Kaksi esimerkkiä

Perintö on ohjelmointirakenne, jota ohjelmistokehittäjät käyttävät perustamiseen on-suhde luokkien välillä. Perinnön avulla voimme johtaa tarkempia luokkia yleisemmistä luokista. Tarkempi luokka on eräänlainen yleisempi luokka. Esimerkiksi sekkitili on eräänlainen tili, jolla voit tehdä talletuksia ja nostaa. Vastaavasti kuorma-auto on eräänlainen ajoneuvo, jota käytetään suurten tavaroiden vetämiseen.

Perintö voi laskeutua useilla tasoilla, mikä johtaa yhä tarkempiin luokkiin. Esimerkkinä kuvassa 1 esitetään auto ja kuorma-auto perimällä ajoneuvosta; farmari periytyy autosta; ja roska-auto peri kuorma-autoista. Nuolet osoittavat tarkemmista "lapsi" -luokista (alhaalta alaspäin) vähemmän erityisiin "vanhempien" luokkiin (ylempänä).

Jeff Friesen

Tämä esimerkki kuvaa yksi perintö jossa lapsiluokka perii tilan ja käyttäytymisen yhdestä välittömästä vanhempaluokasta. Verrattuna, moniperintö mahdollistaa lapsiluokan periä tilan ja käyttäytymisen kahdesta tai useammasta välittömästä vanhempaluokasta. Kuvion 2 hierarkia kuvaa useita perintöjä.

Jeff Friesen

Luokat kuvataan luokittain. Java tukee yhden perinnön kautta luokan laajennus, jossa yksi luokka perii suoraan käytettävissä olevat kentät ja menetelmät toiselta luokalta laajentamalla kyseistä luokkaa. Java ei kuitenkaan tue useita perintöjä luokan laajennuksen kautta.

Kun tarkastelet perintöhierarkiaa, voit helposti tunnistaa useita perintöjä timanttikuvion avulla. Kuvassa 2 on esitetty tämä malli ajoneuvon, maakulkuneuvon, vesikulkuneuvon ja ilmatyynyaluksen yhteydessä.

Laajentaa avainsanan

Java tukee luokan laajennusta ulottuu avainsana. Läsnä ollessa ulottuu määrittää vanhempien ja lasten välisen suhteen kahden luokan välillä. Alla käytän ulottuu luoda suhde luokkien välillä Ajoneuvo ja Autoja sitten välillä Tili ja Säästötili:

Listaus 1. The ulottuu avainsana määrittää vanhemman ja lapsen välisen suhteen

luokka Ajoneuvo {// jäsenilmoitukset} luokka Auto laajentaa ajoneuvoa {// peri esteettömät jäsenet ajoneuvosta // anna omat jäsenilmoitukset} luokka Tili {// jäsenilmoitukset} luokka SäästötTili laajentaa tiliä {// peri käytettävissä olevat jäsenet tililtä // tarjoa omien jäsenten ilmoitukset}

ulottuu avainsana määritetään luokan nimen jälkeen ja ennen toista luokan nimeä. Luokan nimi aiemmin ulottuu tunnistaa lapsen ja luokan nimen jälkeen ulottuu tunnistaa vanhemman. On mahdotonta määrittää useita luokkien nimiä jälkeen ulottuu koska Java ei tue luokkaperusteista useita perintöjä.

Nämä esimerkit kodifioivat is-a-suhteet: Autoon erikoistunut Ajoneuvo ja Säästötilion erikoistunut Tili. Ajoneuvo ja Tili tunnetaan nimellä perusluokkia, vanhempien luokattai superluokkia. Auto ja Säästötili tunnetaan nimellä johdetut luokat, lasten luokattai alaluokat.

Viimeiset luokat

Voit julistaa luokan, jota ei pidä laajentaa; esimerkiksi turvallisuussyistä. Javassa käytämme lopullinen avainsana estää joidenkin luokkien jatkamisen. Yksinkertaisesti lisää etuliitteeseen luokan otsikko lopullinen, kuten viimeisen luokan salasana. Tämän ilmoituksen perusteella kääntäjä ilmoittaa virheestä, jos joku yrittää laajentaa Salasana.

Lapsiluokituksessa peritään käytettävissä olevat kentät ja menetelmät vanhemmilta luokilta ja muilta esi-isiltä. He eivät koskaan peri rakentajia. Sen sijaan lapsiluokat ilmoittavat omat rakentajansa. Lisäksi he voivat ilmoittaa omat kentänsä ja menetelmänsä erottaakseen heidät vanhemmistaan. Harkitse listaa 2.

Listaus 2. An Tili vanhempien luokka

luokan tili {yksityinen merkkijono nimi; yksityinen pitkä summa; Tili (merkkijonon nimi, pitkä summa) {this.name = nimi; setAmount (määrä); } mitätöity talletus (pitkä summa) {tämä.summa + = summa; } Merkkijono getName () {return name; } pitkä getAmount () {palautussumma; } void setAmount (pitkä summa) {this.amount = summa; }}

Listaus 2 kuvaa yleistä pankkitililuokkaa, jolla on nimi ja alkusumma, jotka molemmat on määritetty konstruktorissa. Lisäksi se antaa käyttäjien tehdä talletuksia. (Voit tehdä nostoja tallettamalla negatiivisia rahamääriä, mutta jätämme tämän mahdollisuuden huomiotta.) Huomaa, että tilin nimi on määritettävä tilin luomisen yhteydessä.

Valuutan arvojen esittäminen

pennien määrä. Haluat ehkä käyttää a kaksinkertainen tai a kellua rahallisten arvojen tallentamiseen, mutta se voi johtaa epätarkkuuksiin. Harkitse parempaa ratkaisua BigDecimal, joka on osa Java-standardikurssikirjastoa.

Luettelossa 3 esitetään a Säästötili lapsiluokka, joka laajentaa sen Tili vanhempien luokka.

Listaus 3. A Säästötili lapsiluokka laajentaa Tili vanhempien luokka

class SavingsAccount laajentaa tiliä {SavingsAccount (pitkä summa) {super ("säästöt", summa); }}

Säästötili luokka on triviaali, koska sen ei tarvitse ilmoittaa muita kenttiä tai menetelmiä. Se kuitenkin julistaa konstruktorin, joka alustaa kentät sen kentässä Tili superluokka. Alustus tapahtuu, kun Tilikonstruktoria kutsutaan Java: n kautta super avainsana, jota seuraa sulutettu argumenttiluettelo.

Milloin ja mihin soittaa super ()

Aivan kuten Tämä() täytyy olla konstruktorin ensimmäinen elementti, joka kutsuu toisen saman luokan rakentajan, super () on oltava ensimmäinen elementti konstruktorissa, joka kutsuu konstruktorin yläluokkaansa. Jos rikot tätä sääntöä, kääntäjä ilmoittaa virheestä. Kääntäjä ilmoittaa myös virheestä, jos se havaitsee a super () kutsu menetelmä; vain koskaan soittaa super () konstruktorissa.

Listaus 4 jatkuu edelleen Tili kanssa Tarkistetaan tili luokassa.

Listaus 4. A Tarkistetaan tili lapsiluokka laajentaa Tili vanhempien luokka

class CheckingAccount laajentaa tiliä {CheckingAccount (pitkä summa) {super ("check", summa); } mitätön kotiutus (pitkä summa) {setAmount (getAmount () - summa); }}

Tarkistetaan tili on hieman merkittävämpi kuin Säästötili koska se ilmoittaa a peruuttaa() menetelmä. Huomaa tämän menetelmän kutsut setAmount () ja getAmount (), joka Tarkistetaan tili perii Tili. Et voi käyttää suoraan määrä kenttä Tili koska tämä kenttä on ilmoitettu yksityinen (katso luettelo 2).

super () ja argumenttittomat konstruktorit

Jos super () ei ole määritelty alaluokan rakennuttajassa, ja jos yliluokka ei ilmoita a ei väitettä konstruktori, kääntäjä ilmoittaa virheestä. Tämä johtuu siitä, että alaluokan rakentajan on kutsuttava a ei väitettä superluokan rakentaja kun super () ei ole läsnä.

Luokkahierarkiaesimerkki

Olen luonut AccountDemo sovellusluokka, jonka avulla voit kokeilla Tili luokan hierarkia. Katsokaa ensin AccountDemolähdekoodi.

Listaus 5. AccountDemo osoittaa tililuokan hierarkian

class AccountDemo {public static void main (Merkkijono [] argumentit) {SavingsAccount sa = new SavingsAccount (10000); System.out.println ("tilin nimi:" + sa.getName ()); System.out.println ("alkumäärä:" + sa.getAmount ()); sa. talletus (5000); System.out.println ("uusi summa talletuksen jälkeen:" + sa.getAmount ()); CheckingAccount ca = uusi CheckingAccount (20000); System.out.println ("tilin nimi:" + ca.getName ()); System.out.println ("alkumäärä:" + ca.getAmount ()); noin talletus (6000); System.out.println ("uusi summa talletuksen jälkeen:" + ca.getAmount ()); noin vetäytyi (3000); System.out.println ("uusi summa noston jälkeen:" + ca.getAmount ()); }}

main () Listauksen 5 menetelmä osoittaa ensin Säästötilisitten Tarkistetaan tili. Oletetaan Account.java, SavingsAccount.java, CheckingAccount.javaja AccountDemo.java lähdetiedostot ovat samassa hakemistossa, koota kaikki nämä lähdetiedostot suorittamalla jompikumpi seuraavista komennoista:

javac AccountDemo.java javac * .java

Suorita sovellus suorittamalla seuraava komento:

java AccountDemo

Ota huomioon seuraava tulos:

tilin nimi: säästöjen alkumäärä: 10000 uusi summa talletuksen jälkeen: 15000 tilin nimi: tarkistetaan alkusumma: 20000 uusi summa talletuksen jälkeen: 26000 uusi summa noston jälkeen: 23000

Menetelmän ohittaminen (ja menetelmän ylikuormitus)

Alaluokka voi ohittaa (korvaa) peritty menetelmä siten, että sen sijaan kutsutaan menetelmän alaluokan versiota. Korvaavan menetelmän on määritettävä sama nimi, parametriluettelo ja palautustyyppi kuin ohitettava menetelmä. Osoittaakseni olen ilmoittanut a Tulosta() menetelmä Ajoneuvo luokka alla.

Luettelo 6. Ilmoitus a Tulosta() menetelmä ohitetaan

luokka Ajoneuvo {yksityinen merkkijono; yksityinen merkkijono malli; yksityinen kansainvälinen vuosi; Ajoneuvo (merkkijono, kielimalli, vuosimalli) {this.make = merkki; tämä malli = malli; tämä.vuosi = vuosi; } Merkkijono getMake () {return make; } String getModel () {palautusmalli; } int getYear () {paluuvuosi; } void print () {System.out.println ("Merkki:" + merkki + ", Malli:" + malli + ", Vuosi:" + vuosi); }}

Seuraavaksi ohitan Tulosta() että Kuorma-auto luokassa.

Listaus 7. Korvaava Tulosta() jonkin sisällä Kuorma-auto alaluokka

luokka kuorma-auto jatkuu Ajoneuvo {yksityinen kaksinkertainen vetoisuus; Kuorma-auto (merkkijono, jousimalli, sisävuosi, kaksinkertainen tonnimäärä) {super (merkki, malli, vuosi); this.tonnage = tonnimäärä; } double getTonnage () {paluuvetoisuus; } void print () {super.print (); System.out.println ("Määrä:" + tonnimäärä); }}

Kuorma-autoon Tulosta() menetelmällä on sama nimi, palautustyyppi ja parametriluettelo kuin Ajoneuvoon Tulosta() menetelmä. Huomaa myös se Kuorma-autoon Tulosta() menetelmä ensin kutsuu Ajoneuvoon Tulosta() menetelmä etuliitteellä super. menetelmän nimeen. Usein on hyvä suorittaa ensin yliluokan logiikka ja sitten aliluokan logiikka.

Yliluokan menetelmien kutsuminen alaluokamenetelmistä

Soittaaksesi yliluokan menetelmän ohittavasta aliluokan menetelmästä, lisää menetelmän nimi varattuun sanaan super ja jäsenen käyttöoperaattori. Muuten pääset rekursiivisesti kutsumaan alaluokan ohittavaa menetelmää. Joissakin tapauksissa alaluokka peittää ei-yksityinen superluokan kentät ilmoittamalla samannimiset kentät. Voit käyttää super ja jäsenen käyttöoperaattorin pääsy muihin kuinyksityinen superluokan kentät.

Tämän esimerkin täydentämiseksi olen ote a AjoneuvoDemo luokan main () menetelmä:

Kuorma-auto = uusi kuorma-auto ("Ford", "F150", 2008, 0,5); System.out.println ("Merkki =" + kuorma-auto.getMake ()); System.out.println ("Malli =" + kuorma-auto.getModel ()); System.out.println ("Vuosi =" + kuorma-auto.GetYear ()); System.out.println ("Tonnage =" + kuorma-auto.getTonnage ()); truck.print ();

Viimeinen rivi kuorma-auto.tulos ();, puhelut kuorma-autoon Tulosta() menetelmä. Tämä menetelmä soittaa ensin Ajoneuvoon Tulosta() antaa kuorma-auton merkki, malli ja vuosi; sitten se antaa kuorma-auton vetoisuuden. Tämä tuotoksen osa on esitetty alla:

Merkki: Ford, Malli: F150, Vuosi: 2008 Massa: 0.5

Estä menetelmän ohitus käyttämällä lopullista

Joskus sinun on ehkä ilmoitettava menetelmä, jota ei pidä ohittaa turvallisuuden tai muun syyn vuoksi. Voit käyttää lopullinen avainsana tähän tarkoitukseen. Voit estää ohittamisen yksinkertaisesti etuliittämällä metodin otsikon lopullinen, kuten viimeinen merkkijono getMake (). Kääntäjä ilmoittaa sitten virheestä, jos joku yrittää ohittaa tämän menetelmän alaluokassa.

Menetelmän ylikuormitus vs. ohittaminen

Oletetaan, että olet vaihtanut Tulosta() Listaus 7 -menetelmällä alla olevan menetelmän kanssa:

void print (merkkijonon omistaja) {System.out.print ("Omistaja:" + omistaja); super.tulos (); }

Muokattu Kuorma-auto luokassa on nyt kaksi Tulosta() Methods: edellinen nimenomaisesti ilmoitettu menetelmä ja menetelmä, joka on peritty Ajoneuvo. void print (merkkijonon omistaja) menetelmä ei korvaa Ajoneuvoon Tulosta() menetelmä. Sen sijaan se ylikuormitukset se.

Voit havaita ylikuormitusyrityksen menetelmän korvaamisen sijaan kääntämisajankohtana etuliittämällä aliluokan metodin otsikon @Ohittaa merkintä:

@Override void print (Merkkijonon omistaja) {System.out.print ("Omistaja:" + omistaja); super.tulos (); }

Määritetään @Ohittaa kertoo kääntäjälle, että annettu menetelmä ohittaa toisen menetelmän. Jos joku yritti ylikuormittaa menetelmää sen sijaan, kääntäjä ilmoitti virheestä. Ilman tätä merkintää kääntäjä ei ilmoita virheestä, koska menetelmän ylikuormitus on laillista.

Milloin @Overrideä käytetään

Kehitä tapana etuliittää etusijalla olevat menetelmät @Ohittaa. Tämä tapa auttaa havaitsemaan ylikuormitusvirheet paljon nopeammin.