Zkušení vývojáři Java často považují za samozřejmé funkce Java, které nováčkům připadají matoucí. Například začátečník může být zmatený Objekt
třída. Tento příspěvek uvádí třídílnou sérii, ve které uvádím a odpovídám na otázky Objekt
a jeho metody.
King Object
Otázka: Co je to Objekt
třída?
A: The Objekt
třída, která je uložena v java.lang
balíček, je nejvyšší nadtřídou všech tříd Java (kromě Objekt
). Pole se také rozšiřují Objekt
. Rozhraní se však nerozšiřují Objekt
, na který upozorňuje část 9.6.3.4 Specifikace jazyka Java: ... zvažte, že zatímco rozhraní nemá Objekt
jako supertyp ....
Objekt
deklaruje následující metody, které budu plně diskutovat později v tomto příspěvku a ve zbytku této série:
klon chráněného objektu ()
boolean equals (Object obj)
chráněná prázdnota finalize ()
Třída getClass ()
int hashCode ()
zrušit upozornění ()
void notifyAll ()
String toString ()
void wait ()
neplatné čekání (dlouhý časový limit)
void wait (long timeout, int nanos)
Třída Java zdědí tyto metody a může přepsat jakoukoli metodu, která není deklarována finále
. Napříkladfinále
toString ()
metoda může být přepsána, zatímco finále
Počkejte()
metody nelze přepsat.
Otázka: Mohu výslovně rozšířit Objekt
třída?
A: Ano, můžete to výslovně prodloužit Objekt
. Podívejte se například na výpis 1.
Výpis 1. Explicitně se rozšiřuje Objekt
import java.lang.Object; public class Zaměstnanec rozšiřuje Object {private String name; public Employee (String name) {this.name = name; } public String getName () {zpáteční jméno; } public static void main (String [] args) {Employee emp = new Employee ("John Doe"); System.out.println (emp.getName ()); }}
Můžete sestavit výpis 1 (javac Employee.java
) a spusťte výsledek Zaměstnanec. Třída
soubor (java zaměstnanec
), a budete pozorovat John Doe
jako výstup.
Protože kompilátor automaticky importuje typy z java.lang
balíček, import java.lang.Object;
prohlášení je zbytečné. Java vás také nenutí k výslovnému rozšiřování Objekt
. Pokud ano, nebyli byste schopni rozšířit jiné třídy než Objekt
protože Java omezuje rozšíření třídy na jednu třídu. Proto byste se obvykle rozšířili Objekt
implicitně, jak je uvedeno v seznamu 2.
Výpis 2. Implicitně se rozšiřuje Objekt
public class Employee {private String name; public Employee (String name) {this.name = name; } public String getName () {zpáteční jméno; } public static void main (String [] args) {Employee emp = new Employee ("John Doe"); System.out.println (emp.getName ()); }}
Stejně jako v seznamu 1, seznamu 2 Zaměstnanec
třída se prodlužuje Objekt
a dědí své metody.
Klonování předmětů
Otázka: Co dělá klon ()
metoda dosáhnout?
A: The klon ()
metoda vytvoří a vrátí kopii objektu, na kterém je tato metoda volána.
Otázka: Jak se klon ()
metoda práce?
A:Objekt
nářadí klon ()
jako nativní metoda, což znamená, že její kód je uložen v nativní knihovně. Když se tento kód spustí, zkontroluje třídu (nebo nadtřídu) vyvolávajícího objektu, aby zjistil, zda implementuje java.lang.Cloneable
rozhraní -- Objekt
neprovádí Cloneable
. Pokud toto rozhraní není implementováno, klon ()
hodí java.lang.CloneNotSupportedException
, což je kontrolovaná výjimka (musí být zpracována nebo předána do zásobníku volání metody připojením klauzule throws k záhlaví metody, ve které klon ()
byl vyvolán). Pokud je toto rozhraní implementováno, klon ()
přidělí nový objekt a zkopíruje hodnoty pole volajícího objektu do ekvivalentních polí nového objektu a vrátí odkaz na nový objekt.
Otázka: Jak mohu vyvolat klon ()
metoda klonování objektu?
A: Vzhledem k odkazu na objekt, vyvolat klon ()
na tento odkaz a vrhnout vrácený objekt z Objekt
na typ klonovaného objektu. Výpis 3 představuje příklad.
Výpis 3. Klonování objektu
veřejná třída 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); }}
Výpis 3 deklaruje a CloneDemo
třída, která implementuje Cloneable
rozhraní. Toto rozhraní musí být implementováno nebo vyvoláno Objekt
je klon ()
způsobí vyhodení CloneNotSupportedException
instance.
CloneDemo
deklaruje singl int
- pojmenované pole instance X
a hlavní()
metoda, která tuto třídu procvičuje. hlavní()
je deklarováno pomocí klauzule throws, která projde CloneNotSupportedException
nahoru zásobník volání metod.
hlavní()
první instance CloneDemo
a inicializuje kopii výsledné instance X
na 5
. Potom vydá instance X
hodnotu a vyvolá klon ()
v tomto případě casting vráceného objektu do CloneDemo
před uložením jeho reference. Nakonec vydá klon X
hodnota pole.
Zkompilovat výpis 3 (javac CloneDemo.java
) a spusťte aplikaci (java CloneDemo
). Měli byste dodržovat následující výstup:
cd.x = 5 cd2.x = 5
Otázka: Proč bych musel přepsat klon ()
metoda?
A: Předchozí příklad nepotřeboval přepsat klon ()
metoda, protože kód, který vyvolá klon ()
je umístěn ve třídě, která je klonována (tj CloneDemo
třída). Pokud však klon ()
vyvolání se nachází v jiné třídě, budete muset přepsat klon ()
. Jinak obdržíte „klon má chráněný přístup v Object
"zpráva, protože klon ()
je deklarováno chráněný
. Výpis 4 představuje refaktorovaný výpis 3, který prokazuje přepsání klon ()
.
Výpis 4. Klonování objektu z jiné třídy
třída Data implementuje Cloneable {int x; @Override public Object clone () hodí CloneNotSupportedException {návrat super.clone (); }} veřejná třída 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 Data
třída, jejíž instance mají být klonovány. Tato třída implementuje Cloneable
rozhraní zabránit CloneNotSupportedException
před hozením, když klon ()
metoda se nazývá, deklaruje int
-založené pole instance X
a přepíše klon ()
metoda. Tato metoda se spustí super.clone ()
vyvolat své nadtřídy (Objekt
v tomto příkladu) klon ()
metoda. Naléhavé klon ()
metoda identifikuje CloneNotSupportedException
v klauzuli hází.
Výpis 4 také deklaruje a CloneDemo
třída, která vytváří instanci Data
, inicializuje své pole instance, vypíše hodnotu pole instance této instance, naklonuje Data
instance a vygeneruje hodnotu pole instance této instance.
Zkompilovat výpis 4 (javac CloneDemo.java
) a spusťte aplikaci (java CloneDemo
). Měli byste dodržovat následující výstup:
data.x = 5 data2.x = 5
Otázka: Co je mělké klonování?
A:Mělké klonování (také známý jako mělké kopírování) je duplikace polí objektu bez duplikování jakýchkoli objektů, na které se odkazuje z referenčních polí objektu (pokud existují). Výpisy 3 a 4 ukazují povrchní klonování. Každý z CD
-, cd2
-, data
-, a data2
-referencovaná pole označuje objekt, který má vlastní kopii int
-na základě X
pole.
Mělké klonování funguje dobře, když jsou všechna pole primitivního typu a (v mnoha případech), když se na ně odkazují některá referenční pole neměnný (neměnné) objekty. Pokud jsou však libovolné odkazované objekty proměnlivé, změny provedené v kterémkoli z těchto objektů lze vidět podle původního objektu a jeho klonů. Výpis 5 představuje demonstraci.
Výpis 5. Demonstrace problému s mělkým klonováním v kontextu referenčního pole
třída Zaměstnanec implementuje Cloneable {private String name; soukromý věk; adresa soukromé adresy; Zaměstnanec (jméno řetězce, stáří, adresa) {this.name = name; this.age = věk; this.address = adresa; } @Override public Object clone () hodí CloneNotSupportedException {návrat super.clone (); } Adresa getAddress () {zpáteční adresa; } Řetězec getName () {návratové jméno; } int getAge () {návratový věk; }} třída Adresa {soukromé město řetězce; Adresa (řetězec město) {this.city = city; } String getCity () {návratové město; } 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 ()); Zaměstnanec e2 = (zaměstnanec) 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 ()); }}
Seznam 5 dárků Zaměstnanec
, Adresa
, a CloneDemo
třídy. Zaměstnanec
prohlašuje název
, stáří
, a adresa
pole; a je klonovatelný. Adresa
prohlašuje, že adresa skládající se z města a jeho instancí je proměnlivá. CloneDemo
řídí aplikaci.
CloneDemo
je hlavní()
metoda vytvoří Zaměstnanec
objekt a klonuje tento objekt. Poté změní název města v originále Zaměstnanec
objektu adresa
pole. Protože obojí Zaměstnanec
objekty odkazují stejně Adresa
objekt, oba objekty vidí změněné město.
Zkompilovat výpis 5 (javac CloneDemo.java
) a spusťte tuto aplikaci (java CloneDemo
). Měli byste dodržovat následující výstup:
John Doe: 49: Denver John Doe: 49: Denver John Doe: 49: Chicago John Doe: 49: Chicago
Otázka: Co je hluboké klonování?
A:Hluboké klonování (také známý jako hluboké kopírování) je duplikace polí objektu tak, aby byly duplikovány všechny odkazované objekty. Kromě toho jsou jejich odkazované objekty duplikovány - atd. Například Výpis 6 refaktorů Výpis 5 k využití hlubokého klonování. Rovněž ukazuje typy kovariantních návratů a flexibilnější způsob klonování.
Výpis 6. Hluboké klonování adresa
pole
třída Zaměstnanec implementuje Cloneable {private String name; soukromý věk; adresa soukromé adresy; Zaměstnanec (jméno řetězce, stáří, adresa) {this.name = name; this.age = věk; this.address = adresa; } @Override public Employee clone () hodí CloneNotSupportedException {Employee e = (Employee) super.clone (); e.adresa = address.clone (); návrat e; } Adresa getAddress () {zpáteční adresa; } Řetězec getName () {návratové jméno; } int getAge () {návratový věk; }} třída Adresa {soukromé město řetězce; Adresa (řetězec město) {this.city = city; } @Override public Address clone () {return new Address (new String (city)); } String getCity () {návratové město; } 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 ()); Zaměstnanec e2 = (zaměstnanec) 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 ()); }}
Výpis 6 využívá podporu Java pro kovariantní návratové typy ke změně návratového typu Zaměstnanec
převažuje klon ()
metoda od Objekt
na Zaměstnanec
. Výhodou je, že externí kód Zaměstnanec
může klonovat Zaměstnanec
objekt, aniž by bylo nutné vrhnout tento objekt do Zaměstnanec
typ.
Zaměstnanec
je klon ()
metoda nejprve vyvolá super.clone ()
, který mělce kopíruje název
, stáří
, a adresa
pole. Potom vyvolá klon ()
na adresa
pole pro vytvoření duplikátu odkazovaného Adresa
objekt.
The Adresa
třída přepíše klon ()
metoda a odhaluje několik rozdílů od předchozích tříd, které tuto metodu přepíší:
Adresa
neprovádíCloneable
. Není to nutné, protože jenObjekt
jeklon ()
metoda vyžaduje, aby třída implementovala toto rozhraní a totoklon ()
metoda není volána.- Naléhavé
klon ()
metoda neházíCloneNotSupportedException
. Tato zaškrtnutá výjimka je vyvolána pouze zObjekt
jeklon ()
metoda, která se nevolá. Proto výjimka nemusí být zpracována nebo předána do zásobníku volání metody pomocí klauzule throws. Objekt
jeklon ()
metoda se nevolá (nenísuper.clone ()
volání), protože proAdresa
třída - ke kopírování existuje pouze jedno pole.
Klonovat Adresa
stačí vytvořit nový Adresa
objekt a inicializovat jej na duplikát objektu odkazovaného z město
pole. Nové Adresa
objekt je poté vrácen.