Skúsení vývojári v odbore Java často považujú za samozrejmé funkcie Java, ktoré sú pre nováčikov mätúce. Napríklad začiatočník môže byť z toho zmätený Objekt
trieda. Tento príspevok uvádza na trh trojdielnu sériu, v ktorej uvádzam a odpovedám na otázky Objekt
a jeho metódy.
Kráľ Object
Otázka: Čo je Objekt
trieda?
A: The Objekt
triedy, ktorá je uložená v java.lang
balíček, je najvyššou nadtriedou všetkých tried Java (okrem Objekt
). Polia sa tiež rozširujú Objekt
. Rozhrania sa však nerozširujú Objekt
, na ktorú upozorňuje oddiel 9.6.3.4 špecifikácie jazyka Java: ... zvážte, že zatiaľ čo rozhranie nemá Objekt
ako supertyp ....
Objekt
deklaruje nasledujúce metódy, ktorým sa budem podrobnejšie venovať ďalej v tomto príspevku a vo zvyšku tejto série:
klon chráneného objektu ()
boolean equals (Object obj)
chránená prázdnota finalize ()
Trieda getClass ()
int hashCode ()
void notify ()
void notifyAll ()
String toString ()
neplatné čakanie ()
neplatné čakanie (dlhý časový limit)
void wait (long timeout, int nanos)
Trieda Java dedí tieto metódy a môže prepísať každú metódu, ktorá nie je deklarovaná konečné
. Napríkladkonečné
natiahnuť()
metóda môže byť prepísaná, zatiaľ čo konečné
počkaj ()
metódy nemožno prepísať.
Otázka: Môžem výslovne rozšíriť Objekt
trieda?
A: Áno, môžete to výslovne predĺžiť Objekt
. Napríklad, pozrite si zoznam 1.
Výpis 1. Výslovne sa rozširuje Objekt
import java.lang.Object; public class Zamestnanec rozširuje Object {private String name; public Employee (String name) {this.name = name; } public String getName () {návratové meno; } public static void main (String [] args) {Employee emp = new Employee ("John Doe"); System.out.println (emp.getName ()); }}
Môžete zostaviť záznam 1 (javac Employee.java
) a výsledný výsledok spustite Zamestnanec.trieda
spis (java zamestnanec
), a budete pozorovať John Doe
ako výstup.
Pretože kompilátor automaticky importuje typy z java.lang
balíček, import java.lang.Object;
vyhlásenie je zbytočné. Java vás tiež nenúti výslovne rozširovať Objekt
. Ak by to tak bolo, nemohli by ste rozšíriť iné triedy ako Objekt
pretože Java obmedzuje rozšírenie triedy na jednu triedu. Preto by ste zvyčajne predĺžili Objekt
implicitne, ako je uvedené v zozname 2.
Zoznam 2. Implicitne sa rozširuje Objekt
public class Employee {private String name; public Employee (String name) {this.name = name; } public String getName () {návratové meno; } public static void main (String [] args) {Employee emp = new Employee ("John Doe"); System.out.println (emp.getName ()); }}
Rovnako ako v zozname 1, zozname 2 Zamestnanec
trieda predlžuje Objekt
a dedí svoje metódy.
Klonovanie predmetov
Otázka: Čo robí klon ()
metóda splniť?
A: The klon ()
metóda vytvorí a vráti kópiu objektu, na ktorom sa táto metóda volá.
Otázka: Ako to robí klon ()
metóda práce?
A:Objekt
náradie klon ()
ako natívna metóda, čo znamená, že jej kód je uložený v natívnej knižnici. Keď sa tento kód spustí, skontroluje triedu (alebo nadtriedu) vyvolávajúceho objektu, aby zistil, či implementuje java.lang.Obnoviteľné
rozhranie -- Objekt
nerealizuje Cloneable
. Ak toto rozhranie nie je implementované, klon ()
hodí java.lang.CloneNotSupportedException
, čo je kontrolovaná výnimka (musí sa s ňou manipulovať alebo ju odovzdať do zásobníka volaní metód pridaním klauzuly throws k hlavičke metódy, v ktorej klon ()
bol vyvolaný). Ak je toto rozhranie implementované, klon ()
pridelí nový objekt a skopíruje hodnoty polí volajúceho objektu do ekvivalentných polí nového objektu a vráti odkaz na nový objekt.
Otázka: Ako sa môžem dovolať klon ()
metóda na klonovanie objektu?
A: Vzhľadom na odkaz na objekt, vyvolajte klon ()
na tento odkaz a vrhnúť vrátený objekt z Objekt
podľa typu klonovaného objektu. Výpis 3 predstavuje príklad.
Zoznam 3. Klonovanie objektu
verejná trieda CloneDemo implementuje Cloneable {int x; public static void main (String [] args) hodí CloneNotSupportedException {CloneDemo cd = new CloneDemo (); cd.x = 5; System.out.printf ("cd.x =% d% n", cd.x); CloneDemo cd2 = (CloneDemo) cd.clone (); System.out.printf ("cd2.x =% d% n", cd2.x); }}
Zoznam 3 vyhlasuje a CloneDemo
trieda, ktorá implementuje Cloneable
rozhranie. Toto rozhranie musí byť implementované alebo musí byť vyvolané Objekt
je klon ()
metóda bude mať za následok vyhodenie CloneNotSupportedException
inštancia.
CloneDemo
vyhlasuje za slobodného int
- pomenované pole inštancie X
a a hlavný()
metóda, ktorá túto hodinu precvičuje. hlavný()
je deklarovaná pomocou klauzuly hodov, ktorá prechádza CloneNotSupportedException
do zásobníka metódových volaní.
hlavný()
prvé inštancie CloneDemo
a inicializuje kópiu výslednej inštancie X
do 5
. Potom vydá výstupy inštancie X
hodnotu a vyvoláva klon ()
v tomto prípade casting vráteného objektu na CloneDemo
pred uložením jeho referencie. Nakoniec vydá klon X
hodnota poľa.
Zostaviť zoznam 3 (javac CloneDemo.java
) a spustite aplikáciu (java CloneDemo
). Mali by ste dodržiavať nasledujúci výstup:
cd.x = 5 cd2.x = 5
Otázka: Prečo by som musel prepísať klon ()
metóda?
A: Predchádzajúci príklad nemusel prepísať klon ()
metóda, pretože kód, ktorý vyvoláva klon ()
sa nachádza v triede, ktorá sa klonuje (t. j CloneDemo
trieda). Ak však klon ()
vyvolanie sa nachádza v inej triede, budete musieť prepísať klon ()
. V opačnom prípade dostaneteklon má chránený prístup v objekte
„správa, pretože klon ()
je vyhlásený chránené
. Zoznam 4 predstavuje prepracovaný zoznam 3, ktorý demonštruje prepísanie klon ()
.
Výpis 4. Klonovanie objektu z inej triedy
trieda Dátové implementácie Cloneable {int x; @Override public Object clone () hodí CloneNotSupportedException {return super.clone (); }} public class CloneDemo {public static void main (String [] args) hodí CloneNotSupportedException {Data data = new Data (); data.x = 5; System.out.printf ("data.x =% d% n", data.x); Data data2 = (Data) data.clone (); System.out.printf ("data2.x =% d% n", data2.x); }}
Výpis 4 deklaruje a Údaje
triedy, ktorej inštancie sa majú klonovať. Táto trieda implementuje Cloneable
rozhranie zabrániť CloneNotSupportedException
pred vyhodením, keď klon ()
metóda sa volá, deklaruje int
- inštančné pole X
a prepíše klon ()
metóda. Táto metóda sa vykoná super.clone ()
vyvolať svoju nadtriedu (Objekt
v tomto príklade) klon ()
metóda. Naliehavé klon ()
metóda identifikuje CloneNotSupportedException
v klauzule jeho hodov.
Zoznam 4 tiež deklaruje a CloneDemo
trieda, ktorá vytvára inštancie Údaje
, inicializuje svoje inštančné pole, odošle hodnotu tohto inštančného poľa, klonuje Údaje
inštancia a na výstup privádza hodnotu poľa inštancie tejto inštancie.
Zostaviť zoznam 4 (javac CloneDemo.java
) a spustite aplikáciu (java CloneDemo
). Mali by ste dodržiavať nasledujúci výstup:
data.x = 5 data2.x = 5
Otázka: Čo je plytké klonovanie?
A:Plytké klonovanie (taktiež známy ako plytké kopírovanie) je duplikácia polí objektu bez duplikovania akýchkoľvek objektov, na ktoré sa odkazuje z referenčných polí objektu (ak existuje). Výpisy 3 a 4 demonštrujú povrchné klonovanie. Každá z cd
-, cd2
-, údaje
- a data2
-referencované polia identifikujú objekt, ktorý má svoju vlastnú kópiu int
- na základe X
lúka.
Plytké klonovanie funguje dobre, keď sú všetky polia primitívneho typu a (v mnohých prípadoch), keď sa na ne odkazuje nejaké referenčné pole nemenný (nemeniteľné) predmety. Ak sú však niektoré odkazované objekty zmeniteľné, pôvodný objekt a jeho klon (y) môžu vidieť zmeny vykonané v ktoromkoľvek z týchto objektov. Zoznam 5 predstavuje demonštráciu.
Zoznam 5. Preukázanie problému s plytkým klonovaním v kontexte referenčného poľa
trieda Zamestnanec implementuje Cloneable {private String name; súkromný int vek; adresa súkromnej adresy; Zamestnanec (meno reťazca, vek, adresa) {this.name = meno; this.age = vek; this.address = adresa; } @Override public Object clone () hodí CloneNotSupportedException {return super.clone (); } Adresa getAddress () {spiatočná adresa; } Reťazec getName () {návratové meno; } int getAge () {návratový vek; }} trieda Adresa {private String city; Adresa (reťazec mesto) {this.city = city; } String getCity () {return city; } void setCity (String city) {this.city = city; }} public class CloneDemo {public static void main (String [] args) throws CloneNotSupportedException {Employee e = new Employee ("John Doe", 49, new Address ("Denver")); System.out.printf ("% s:% d:% s% n", e.getName (), e.getAge (), e.getAddress (). GetCity ()); Zamestnanec e2 = (zamestnanec) e.clone (); 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 ()); }}
Zoznam 5 darčekov Zamestnanec
, Adresa
a CloneDemo
triedy. Zamestnanec
vyhlasuje názov
, Vek
a adresa
polia; a je klonovateľný. Adresa
vyhlasuje, že adresa pozostávajúca z mesta a jeho inštancií je premenlivá. CloneDemo
riadi aplikáciu.
CloneDemo
je hlavný()
metóda vytvára Zamestnanec
objekt a klonuje tento objekt. Potom sa zmení pôvodný názov mesta Zamestnanec
objektu adresa
lúka. Pretože oboje Zamestnanec
objekty odkazujú rovnako Adresa
objekt, zmenené mesto vidia oba objekty.
Zostaviť zoznam 5 (javac CloneDemo.java
) a spustite túto aplikáciu (java CloneDemo
). Mali by ste dodržiavať nasledujúci výstup:
John Doe: 49: Denver John Doe: 49: Denver John Doe: 49: Chicago John Doe: 49: Chicago
Otázka: Čo je hlboké klonovanie?
A:Hlboké klonovanie (taktiež známy ako hlboké kopírovanie) je duplikácia polí objektu tak, aby boli duplikované všetky odkazované objekty. Ďalej sú ich odkazované objekty duplikované - a tak ďalej. Napríklad zoznam 6 refaktorov uvedených v zozname 5 na využitie hlbokého klonovania. Ukazuje tiež typy kovariančných návratov a flexibilnejší spôsob klonovania.
Zoznam 6. Hlboké klonovanie adresa
lúka
trieda Zamestnanec implementuje Cloneable {private String name; súkromný int vek; adresa súkromnej adresy; Zamestnanec (meno reťazca, vek, adresa) {this.name = meno; this.age = vek; this.address = adresa; } @Override public Employee clone () hodí CloneNotSupportedException {Employee e = (Employee) super.clone (); e.adresa = adresa.klon (); návrat e; } Adresa getAddress () {spiatočná adresa; } Reťazec getName () {návratové meno; } int getAge () {návratový vek; }} trieda Adresa {private String city; Adresa (reťazec mesto) {this.city = city; } @Override public Address clone () {return new Address (new String (city)); } String getCity () {return city; } void setCity (String city) {this.city = city; }} public class CloneDemo {public static void main (String [] args) throws CloneNotSupportedException {Employee e = new Employee ("John Doe", 49, new Address ("Denver")); System.out.printf ("% s:% d:% s% n", e.getName (), e.getAge (), e.getAddress (). GetCity ()); Zamestnanec e2 = (zamestnanec) e.clone (); 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 ()); }}
Zoznam 6 využíva podporu Javy pre kovariantné návratové typy na zmenu návratového typu Zamestnanec
je prvoradý klon ()
metóda z Objekt
do Zamestnanec
. Výhodou je, že externý kód je Zamestnanec
môže klonovať Zamestnanec
objekt bez toho, aby ste tento objekt museli odovzdať Zamestnanec
typu.
Zamestnanec
je klon ()
metóda najskôr vyvolá super.clone ()
, ktorý povrchne kopíruje názov
, Vek
a adresa
polia. Potom sa vyvolá klon ()
na adresa
pole na vytvorenie duplikátu referencovaného Adresa
objekt.
The Adresa
trieda prepíše klon ()
metóda a odhaľuje niekoľko rozdielov od predchádzajúcich tried, ktoré túto metódu prepisujú:
Adresa
nerealizujeCloneable
. Nie je to potrebné, pretože ibaObjekt
jeklon ()
metóda vyžaduje, aby trieda implementovala toto rozhranie a totoklon ()
metóda sa nevolá.- Naliehavé
klon ()
metóda nehádžeCloneNotSupportedException
. Táto zaškrtnutá výnimka je vyvolaná iba zObjekt
jeklon ()
metóda, ktorá sa nevolá. Výnimka preto nemusí byť spracovaná alebo odovzdaná do zásobníka volaní metód cez klauzulu throws. Objekt
jeklon ()
metóda sa nevolá (nie jesuper.clone ()
volanie), pretože plynulé kopírovanie sa nevyžaduje preAdresa
trieda - existuje iba jedno pole na kopírovanie.
Klonovať Adresa
objekt, stačí vytvoriť nový Adresa
objekt a inicializujte ho na duplikát objektu odkazovaného z mesto
lúka. Nové Adresa
objekt sa potom vráti.