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-lopullinen
toString ()
menetelmä voidaan ohittaa, kun taas lopullinen
odota()
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 Esine
on 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ä x
ja ohittaa klooni()
menetelmä. Tämä menetelmä suoritetaan super.klooni ()
vedota sen superluokkaan (Esine
tä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ä
, Osoite
ja 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.
Kloonidemo
on 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 toteutaKloonattava
. Se ei ole välttämätöntä, koska vainEsine
onklooni()
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 kohteestaEsine
onklooni()
menetelmä, jota ei kutsuta. Siksi poikkeusta ei tarvitse käsitellä tai siirtää metod-call -pinoa heittolausekkeen kautta. Esine
onklooni()
menetelmää ei kutsuta (ei olesuper.klooni ()
puhelu), koska matalaa kopiointia ei vaaditaOsoite
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.