Ohjelmointi

Perintö Javaissa, osa 2: Objekti ja sen menetelmät

Java tarjoaa tavallisen luokkakirjaston, joka koostuu tuhansista luokista ja muista viitetyypeistä. Hyvyydestään eroavaisuudesta huolimatta nämä tyypit muodostavat yhden massiivisen perintöhierarkian laajentamalla suoraan tai epäsuorasti Esine luokassa. Tämä pätee myös luomaasi luokkaan ja muuhun viitetyyppiin.

Tämän Java-perinnön opetusohjelman alkupuoliskolla saatiin esille perinnön perusteet ja erityisesti Java-ohjelmien käyttöulottuu ja super avainsanat, joilla johdetaan lapsiluokka vanhempien luokasta, vedetään vanhempien luokan rakentajiin ja menetelmiin, ohitetaan menetelmiä ja muuta. Nyt keskitymme Java-luokan perintöhierarkian emolevyyn, java.lang.objekti.

Opiskelu Esine ja sen menetelmät auttavat sinua saamaan toiminnallisemman käsityksen perinnöstä ja siitä, miten se toimii Java-ohjelmissasi. Noiden menetelmien tuntemus auttaa ymmärtämään Java-ohjelmia yleensä.

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

Kohde: Java: n superluokka

Esine on kaikkien muiden Java-luokkien juuriluokka tai perimmäinen superluokka. Tallennettu java.lang paketti, Esine julistaa seuraavat menetelmät, jotka kaikki muut luokat perivät:

  • suojattu objektiklooni ()
  • looginen arvo on yhtä suuri (Object obj)
  • suojattu void viimeistele ()
  • Luokka getClass ()
  • int hashCode ()
  • mitätön ilmoitus ()
  • mitätön ilmoitusAll ()
  • Merkkijono merkkijonolle ()
  • mitätöi odota ()
  • mitätön odotus (pitkä aikakatkaisu)
  • mitätön odotus (pitkä aikakatkaisu, int nanos)

Java-luokka perii nämä menetelmät ja voi ohittaa minkä tahansa menetelmän, jota ei ole ilmoitettu lopullinen. Esimerkiksi ei-lopullinentoString () menetelmä voidaan ohittaa, kun taas lopullinenodota() menetelmät eivät voi.

Tarkastelemme kaikkia näitä menetelmiä ja miten niiden avulla voit suorittaa erityistehtäviä Java-luokkiesi yhteydessä. Tarkastellaan ensin perussääntöjä ja -mekanismeja Esine perintö.

Yleiset tyypit

Olet ehkä huomannut yllä olevassa luettelossa getClass (), jonka Luokka palautustyyppi on esimerkki a yleinen tyyppi. Keskustelen yleisistä tyypeistä tulevassa artikkelissa.

Objektin laajentaminen: Esimerkki

Luokka voi nimenomaisesti laajentaa Esine, kuten luettelo 1 osoittaa.

Listaus 1. Objektin nimenomainen laajentaminen

public class Työntekijä laajentaa Object {private String name; public Employee (String name) {tämä.nimi = nimi; } public String getName () {palautusnimi; } public static void main (Merkkijono [] argumentti) {Employee emp = new Employee ("John Doe"); System.out.println (emp.getName ()); }}

Koska voit laajentaa enintään yhtä muuta luokkaa (muista osasta 1, että Java ei tue luokkaperusteista useita perintöjä), et ole pakko nimenomaisesti laajentaa Esine; muuten et voinut laajentaa mitään muuta luokkaa. Siksi jatkaisit Esine epäsuorasti, kuten luettelo 2 osoittaa.

Listaus 2. Objektin implisiittisesti laajentaminen

julkinen luokka Työntekijä {yksityinen String nimi; julkinen työntekijä (merkkijono) {tämä.nimi = nimi; } public String getName () {palautusnimi; } public static void main (Merkkijono [] argumentti) {Employee emp = new Employee ("John Doe"); System.out.println (emp.getName ()); }}

Koosta Listing 1 tai Listing 2 seuraavasti:

javac Employee.java

Suorita tuloksena oleva sovellus:

java Työntekijä

Ota huomioon seuraava tulos:

John Doe

Lisätietoja luokasta: getClass ()

getClass () method palauttaa minkä tahansa objektin ajon luokan, johon sitä kutsutaan. ajonaikainen luokka on a Luokka esine, joka löytyy java.lang paketti. Luokka on lähtökohta Java Reflection -sovellusliittymään, josta opit, kun käsittelemme edistyneempiä aiheita Java-ohjelmoinnissa. Toistaiseksi tiedä, että Java-sovellus käyttää Luokka ja loput Java Reflection -sovellusliittymästä oppiaksesi sen omasta rakenteesta.

Luokan objektit ja staattiset synkronoidut menetelmät

Palasi Luokka objekti on lukittu objekti staattinen synkronoitu edustetun luokan menetelmät; esimerkiksi, staattinen synkronoitu void foo () {}. (Esittelen Java-synkronoinnin tulevassa opetusohjelmassa.)

Objektien kopiointi: klooni ()

klooni() method luo ja palauttaa kopion objektista, johon sitä kutsutaan. Koska klooni()Palautustyyppi on Esine, objekti viittaa siihen klooni() palautukset on lähetettävä objektin todelliseen tyyppiin, ennen kuin viittaus määritetään objektityypin muuttujalle. Listaus 3 esittää sovelluksen, joka osoittaa kloonauksen.

Listaus 3. Objektin kloonaus

luokka CloneDemo toteuttaa Cloneable {int x; public static void main (String [] args) heittää CloneNotSupportedException {CloneDemo cd = new CloneDemo (); cdx = 5; System.out.println ("cd.x =" + cd.x); CloneDemo cd2 = (CloneDemo) cd. klooni (); System.out.println ("cd2.x =" + cd2.x); }}

Luettelo 3: sta Kloonidemo luokka toteuttaa Kloonattava käyttöliittymä, joka löytyy java.lang paketti. Kloonattava luokan toteuttaa ( työvälineet avainsana) estääksesi Esineon klooni() - tapa heittää CloneNotSupportedException luokka (löytyy myös java.lang).

Kloonidemo julistaa yhden int-perusteisen ilmentymän kentän nimi x ja a main () menetelmä, joka harjoittaa tätä luokkaa. main () ilmoitetaan a: lla heittää lauseke, joka kulkee CloneNotSupportedException ylöspäin menetelmä-kutsupino.

main () ensin instantiates Kloonidemo ja alustaa tuloksena olevan instanssin kopion x että 5. Sitten se tuottaa instanssin x arvo ja puhelut klooni() tässä tapauksessa palautetun objektin heittäminen kohteeseen Kloonidemo ennen viitteen tallentamista. Lopuksi se tuottaa kloonin x kentän arvo.

Koosta luettelo 3 (javac CloneDemo.java) ja suorita sovellus (java CloneDemo). Ota huomioon seuraava tulos:

cd.x = 5 cd2.x = 5

Korvaava klooni ()

Edellisen esimerkin ei tarvinnut ohittaa klooni() koska koodi, joka kutsuu klooni() sijaitsee kloonatussa luokassa (Kloonidemo). Jos soitat klooni() sijaitsivat kuitenkin toisessa luokassa, sinun pitäisi sitten ohittaa klooni(). Koska klooni() ilmoitetaan suojattu, saisit "klooni on suojattu pääsy Object"-viesti, jos et ohittanut sitä ennen luokan kokoamista. Listaus 4 esittää uudistetun luettelon 3, joka osoittaa ohittavan klooni().

Listaus 4. Objektin kloonaus toisesta luokasta

luokka Datatyökalut Cloneable {int x; @Override public Object clone () heittää CloneNotSupportedException {return super.clone (); }} luokka CloneDemo {public static void main (String [] args) heittää CloneNotSupportedException {Data data = new Data (); data x = 5; System.out.println ("data.x =" + data.x); Data data2 = (data) data.klooni (); System.out.println ("data2.x =" + data2.x); }}

Listaus 4 ilmoittaa a Tiedot luokka, jonka esiintymät on kloonattava. Tiedot toteuttaa Kloonattava käyttöliittymä estää a CloneNotSupportedException heittämästä, kun klooni() menetelmää kutsutaan. Sitten se julistaa int-pohjainen instanssikenttä xja ohittaa klooni() menetelmä. klooni() menetelmä suoritetaan super.klooni () kutsua sen superluokkaa (eli Esinen) klooni() menetelmä. Ylivoimainen klooni() menetelmä tunnistaa CloneNotSupportedException sen heittää lauseke.

Listaus 4 ilmoittaa myös a Kloonidemo luokka, joka: instantizes Tiedot, alustaa ilmentymäkentän, antaa ilmentymäkentän arvon, kloonaa Tiedot objekti ja antaa sen ilmentymäkentän arvon.

Koosta luettelo 4 (javac CloneDemo.java) ja suorita sovellus (java CloneDemo). Ota huomioon seuraava tulos:

data.x = 5 data2.x = 5

Matala kloonaus

Matala kloonaus (tunnetaan myös matala kopiointi) viittaa objektin kenttien kopiointiin kopioimatta objekteja, joihin viitataan kyseisen objektin viitekentistä (jos referenssikenttiä on). Luettelot 3 ja 4 osoittivat todella matalan kloonauksen. Jokainen CD-, cd2-, tiedot- ja tiedot 2-viitekentät identifioivat objektin, jolla on oma kopio int-perustuu x ala.

Matala kloonaus toimii hyvin, kun kaikki kentät ovat primitiivisiä ja (monissa tapauksissa), kun viitekentät viittaavat muuttumaton (muuttumattomia) esineitä. Kuitenkin, jos jokin viitattu objekti on muutettavissa, alkuperäinen objekti ja sen klooni (t) näkevät mihin tahansa näistä kohteista tehdyt muutokset. Listaus 5 osoittaa.

Listaus 5. Matala kloonaus on ongelma viitekentän yhteydessä

luokka Työntekijä toteuttaa Cloneable {private String name; yksityinen ikä; yksityinen Osoite-osoite; Työntekijä (merkkijonon nimi, ikä, osoitteen osoite) {this.name = nimi; tämä. ikä = ikä; tämä.osoite = osoite; } @Override public Object clone () heittää CloneNotSupportedException {return super.clone (); } Osoite getAddress () {palautusosoite; } Merkkijono getName () {return name; } int getAge () {paluuikä; }} luokka Osoite {yksityinen Merkkijono kaupunki; Osoite (merkkijono kaupunki) {this.city = kaupunki; } String getCity () {paluukaupunki; } void setCity (merkkijono) {this.city = kaupunki; }} luokka CloneDemo {public static void main (String [] args) heittää CloneNotSupportedException {Employee e = new Employee ("John Doe", 49, uusi osoite ("Denver")); System.out.println (e.getName () + ":" + e.getAge () + ":" + e.getAddress (). GetCity ()); Työntekijä e2 = (Työntekijä) e.klooni (); System.out.println (e2.getName () + ":" + e2.getAge () + ":" + e2.getAddress (). GetCity ()); e.getAddress (). setCity ("Chicago"); System.out.println (e.getName () + ":" + e.getAge () + ":" + e.getAddress (). GetCity ()); System.out.println (e2.getName () + ":" + e2.getAge () + ":" + e2.getAddress (). GetCity ()); }}

Luettelossa 5 lahjaa Työntekijä, Osoiteja Kloonidemo luokat. Työntekijä julistaa nimi, ikäja osoite kentät; ja on kloonattava. Osoite julistaa kaupungin muodostavan osoitteen ja sen esiintymät ovat muutettavissa. Kloonidemo ajaa sovellusta.

Kloonidemoon main () menetelmä luo Työntekijä ja kloonaa tämän objektin. Sitten se muuttaa kaupungin nimen alkuperäisessä muodossa Työntekijä esine osoite ala. Koska molemmat Työntekijä objektit viittaavat samaan Osoite esine, molemmat kohteet näkevät muuttuneen kaupungin.

Koosta luettelo 5 (javac CloneDemo.java) ja suorita tämä sovellus (java CloneDemo). Ota huomioon seuraava tulos:

John Doe: 49: Denver John Doe: 49: Denver John Doe: 49: Chicago John Doe: 49: Chicago

Syvä kloonaus

Syvä kloonaus (tunnetaan myös syvä kopiointi) viittaa objektin kenttien kopiointiin siten, että kaikki viitatut objektit kopioidaan. Lisäksi viitattujen objektien viitatut objektit kopioidaan ja niin edelleen. Listaus 6 refaktoria Listaus 5 syvän kloonauksen osoittamiseksi.

Listaus 6. Osoitekentän syvä kloonaus

luokka Työntekijä toteuttaa Cloneable {private String name; yksityinen ikä; yksityinen Osoite-osoite; Työntekijä (merkkijonon nimi, ikä, osoitteen osoite) {this.name = nimi; tämä. ikä = ikä; tämä.osoite = osoite; } @Override public Object clone () heittää CloneNotSupportedException {Employee e = (Employee) super.clone (); e.osoite = (Osoite) osoite.klooni (); paluu e; } Osoite getAddress () {palautusosoite; } Merkkijono getName () {return name; } int getAge () {paluuikä; }} luokka Osoite {yksityinen Merkkijono kaupunki; Osoite (merkkijono kaupunki) {this.city = kaupunki; } @Override public Object clone () {return new Address (new String (city)); } String getCity () {paluukaupunki; } void setCity (merkkijono) {this.city = kaupunki; }} luokka CloneDemo {public static void main (String [] args) heittää CloneNotSupportedException {Employee e = new Employee ("John Doe", 49, uusi osoite ("Denver")); System.out.println (e.getName () + ":" + e.getAge () + ":" + e.getAddress (). GetCity ()); Työntekijä e2 = (Työntekijä) e.klooni (); System.out.println (e2.getName () + ":" + e2.getAge () + ":" + e2.getAddress (). GetCity ()); e.getAddress (). setCity ("Chicago"); System.out.println (e.getName () + ":" + e.getAge () + ":" + e.getAddress (). GetCity ()); System.out.println (e2.getName () + ":" + e2.getAge () + ":" + e2.getAddress (). GetCity ()); }}

Listaus 6 osoittaa sen Työntekijäon klooni() menetelmä ensin kutsuu super.klooni (), joka kopioi matalasti nimi, ikäja osoite kentät. Sitten se soittaa klooni() on osoite -kenttään tehdäksesi kopion viitatusta Osoite esine. Osoite ohittaa klooni() menetelmä ja paljastaa muutamia eroja aiempiin luokkiin, jotka ohittavat tämän menetelmän:

  • Osoite ei toteuta Kloonattava. Se ei ole välttämätöntä, koska vain Esineon klooni() menetelmä edellyttää, että luokka toteuttaa tämän käyttöliittymän, ja tämä klooni() menetelmää ei kutsuta.
  • Ylivoimainen klooni() menetelmä ei heitä CloneNotSupportedException. Tämä poikkeus heitetään vain Esineon klooni() menetelmä, jota ei kutsuta. Siksi poikkeusta ei tarvitse käsitellä tai siirtää metod-call -pinoa heittolausekkeen kautta.
  • Esineon klooni() menetelmää ei kutsuta (ei ole super.klooni () puhelu), koska matalaa kopiointia ei vaadita Osoite luokka - kopioitavana on vain yksi kenttä.