Ohjelmointi

Perimmäinen superluokka, osa 1

Kokeneet Java-kehittäjät pitävät usein itsestään selvinä Java-ominaisuuksia, jotka uudet tulijat pitävät hämmentävänä. Esimerkiksi aloittelija voi olla hämmentynyt Esine luokassa. Tämä viesti käynnistää kolmiosaisen sarjan, jossa esitän ja vastaan ​​kysymyksiin Esine ja sen menetelmät.

Kuningas Object

K: Mikä on Esine luokka?

A: Esine luokka, joka on tallennettu java.lang paketti, on kaikkien Java-luokkien (paitsi Esine). Myös taulukot laajenevat Esine. Liitännät eivät kuitenkaan ulotu Esine, joka on esitetty Java-kielimäärityksen kohdassa 9.6.3.4: ... katsovat, että vaikka käyttöliittymällä ei ole Esine supertyyppinä ....

Esine julistaa seuraavat menetelmät, joista keskustelen täysin myöhemmin tässä viestissä ja muussa sarjassa:

  • 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() menetelmiä ei voida ohittaa.

K: Voinko nimenomaisesti laajentaa Esine luokka?

A: Kyllä, voit nimenomaisesti laajentaa Esine. Katso esimerkiksi Listaus 1.

Listaus 1. Laajentuu nimenomaisesti Esine

tuo java.lang.Object; public class Työntekijä laajentaa Object {private String name; 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 ()); }}

Voit koota Listing 1 (javac Employee.java) ja suorita tuloksena oleva tulos Employee.class tiedosto (java Työntekijä), ja huomaat John Doe tuotoksena.

Koska kääntäjä tuo tyypit automaattisesti java.lang paketti tuo java.lang.Object; lausunto on tarpeeton. Java ei myöskään pakota sinua nimenomaisesti laajentamaan Esine. Jos se tekisi, et voisi laajentaa muita luokkia kuin Esine koska Java rajoittaa luokan laajennuksen yhteen luokkaan. Siksi jatkat tyypillisesti Esine epäsuorasti, kuten luettelo 2 osoittaa.

Listaus 2. Implisiittisesti jatkuva Esine

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 ()); }}

Kuten luettelossa 1, luettelossa 2 Työntekijä luokka jatkuu Esine ja perii menetelmänsä.

Esineiden kloonaus

K: Mitä klooni() menetelmä saavuttaa?

A: klooni() method luo ja palauttaa kopion objektista, johon tätä menetelmää kutsutaan.

K: Kuinka klooni() menetelmä toimii?

A:Esine työvälineet klooni() natiivimenetelmänä, mikä tarkoittaa, että sen koodi on tallennettu natiivikirjastoon. Kun tämä koodi suoritetaan, se tarkistaa kutsuvan objektin luokan (tai yläluokan) varmistaakseen, toteuttaakö se koodin java.lang. kloonattava käyttöliittymä -- Esine ei toteuta Kloonattava. Jos tätä käyttöliittymää ei ole otettu käyttöön, klooni() heittää java.lang.CloneNotSupportedException, joka on tarkistettu poikkeus (se on käsiteltävä tai siirrettävä metodi-kutsu pino lisäämällä heittolauseke menetelmän otsikkoon klooni() käytettiin). Jos tämä käyttöliittymä on otettu käyttöön, klooni() allokoi uuden objektin ja kopioi kutsuvan objektin kentän arvot uuden objektin vastaaviin kenttiin ja palauttaa viitteen uuteen objektiin.

K: Kuinka voin vedota klooni() menetelmä kloonata objekti?

A: Annetaan objektiviite, vedä klooni() tähän viitteeseen ja heitä palautettu esine kohteesta Esine kloonattavan objektin tyyppiin. Luettelossa 3 on esimerkki.

Listaus 3. Objektin kloonaus

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

Listaus 3 ilmoittaa a Kloonidemo luokka, joka toteuttaa Kloonattava käyttöliittymä. Tämä käyttöliittymä on toteutettava tai sen on kutsuttava Esineon klooni() menetelmä johtaa heittoon CloneNotSupportedException ilmentymä.

Kloonidemo julistaa yhden int-perusteisen ilmentymän kentän nimi x ja a main () menetelmä, joka harjoittaa tätä luokkaa. main () ilmoitetaan heittolausekkeella, joka läpäisee 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 kutsuu 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

K: Miksi minun pitäisi ohittaa klooni() menetelmä?

A: Edellisen esimerkin ei tarvinnut ohittaa klooni() menetelmä, koska kutsuva koodi klooni() sijaitsee kloonatussa luokassa (eli Kloonidemo luokka). Kuitenkin, jos klooni() kutsu sijaitsee eri luokassa, sinun on ohitettava klooni(). Muussa tapauksessa saat "klooni on suojattu pääsy Object"viesti koska klooni() ilmoitetaan suojattu. 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 (); }} public class CloneDemo {public static void main (String [] args) heittää CloneNotSupportedException {Data data = new Data (); data x = 5; System.out.printf ("data.x =% d% n", data.x); Data data2 = (data) data.klooni (); System.out.printf ("data2.x =% d% n", data2.x); }}

Listaus 4 ilmoittaa a Tiedot luokka, jonka esiintymät on kloonattava. Tämä luokka toteuttaa Kloonattava käyttöliittymä estää CloneNotSupportedException heittämästä, kun klooni() menetelmää kutsutaan, julistaa int-pohjainen instanssikenttä xja ohittaa klooni() menetelmä. Tämä menetelmä suoritetaan super.klooni () vedota sen superluokkaan (Esinetässä esimerkissä) klooni() menetelmä. Ylivoimainen klooni() menetelmä tunnistaa CloneNotSupportedException sen heittolausekkeessa.

Listaus 4 ilmoittaa myös a Kloonidemo luokka, joka ilmentää Tiedot, alustaa ilmentymäkentän, antaa tämän ilmentymän kentän arvon, kloonaa Tiedot ja antaa tämän ilmentymän ilmentymän kentän arvon.

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

data.x = 5 data2.x = 5

K: Mitä on matala kloonaus?

A:Matala kloonaus (tunnetaan myös matala kopiointi) on objektin kenttien kopiointi kopioimatta mitään objekteja, joihin viitataan objektin viitekentistä (jos sillä on). Luettelot 3 ja 4 osoittavat 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 viittauskentä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. Luettelossa 5 on esittely.

Listaus 5. Matalan kloonauksen ongelman osoittaminen 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; }} public class CloneDemo {public static void main (String [] args) heittää CloneNotSupportedException {Employee e = new Employee ("John Doe", 49, uusi osoite ("Denver")); System.out.printf ("% s:% d:% s% n", e.getName (), e.getAge (), e.getAddress (). GetCity ()); Työntekijä e2 = (Työntekijä) e.klooni (); System.out.printf ("% s:% d:% s% n", e2.getName (), e2.getAge (), e2.getAddress (). GetCity ()); e.getAddress (). setCity ("Chicago"); System.out.printf ("% s:% d:% s% n", e.getName (), e.getAge (), e.getAddress (). GetCity ()); System.out.printf ("% s:% d:% s% n", 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

K: Mikä on syvä kloonaus?

A:Syvä kloonaus (tunnetaan myös syvä kopiointi) on objektin kenttien kopiointi siten, että kaikki viitatut objektit kopioidaan. Lisäksi niiden viitatut objektit kopioidaan - ja niin edelleen. Esimerkiksi Listing 6 refactors Listing 5 syvän kloonauksen hyödyntämiseksi. Se osoittaa myös kovariaaniset palautustyypit ja joustavamman tavan kloonata.

Listaus 6. Syvän kloonaus osoite ala

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 Employee clone () heittää CloneNotSupportedException {Employee e = (Employee) super.clone (); e.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 address clone () {return new Address (new String (city)); } String getCity () {paluukaupunki; } void setCity (merkkijono) {this.city = kaupunki; }} public class CloneDemo {public static void main (String [] args) heittää CloneNotSupportedException {Employee e = new Employee ("John Doe", 49, uusi osoite ("Denver")); System.out.printf ("% s:% d:% s% n", e.getName (), e.getAge (), e.getAddress (). GetCity ()); Työntekijä e2 = (Työntekijä) e.klooni (); System.out.printf ("% s:% d:% s% n", e2.getName (), e2.getAge (), e2.getAddress (). GetCity ()); e.getAddress (). setCity ("Chicago"); System.out.printf ("% s:% d:% s% n", e.getName (), e.getAge (), e.getAddress (). GetCity ()); System.out.printf ("% s:% d:% s% n", e2.getName (), e2.getAge (), e2.getAddress (). GetCity ()); }}

Listaus 6 hyödyntää Java-tukea kovariaanisille paluutyypeille palautustyypin muuttamiseksi Työntekijäon tärkeämpää klooni() menetelmä Esine että Työntekijä. Etuna on, että koodi on ulkopuolinen Työntekijä voi kloonata Työntekijä objektia tarvitsematta heittää tätä objektia Työntekijä tyyppi.

Työntekijäon klooni() menetelmä vetoaa ensin super.klooni (), joka kopioi matalasti nimi, ikäja osoite kentät. Sitten se vetoaa klooni() on osoite -kenttään tehdäksesi kopion viitatusta Osoite esine.

Osoite luokka 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ä tarkistettu poikkeus heitetään vain kohteesta 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ä.

Kloonata Osoite esine, riittää luoda uusi Osoite objekti ja alustaa se kaksoiskappaleeksi objektista, johon viitataan kaupunki ala. Uusi Osoite objekti palautetaan sitten.

$config[zx-auto] not found$config[zx-overlay] not found