Java poskytuje standardní knihovnu tříd skládající se z tisíců tříd a dalších referenčních typů. Navzdory rozdílům v jejich schopnostech tvoří tyto typy jednu masivní hierarchii dědičnosti přímým nebo nepřímým rozšířením Objekt
třída. To platí také pro všechny třídy a další typy odkazů, které vytvoříte.
První polovina tohoto tutoriálu o dědičnosti Java vám ukázala základy dědičnosti, konkrétně jak používat Javurozšiřuje
a super
klíčová slova pro odvození podřízené třídy z nadřazené třídy, vyvolání konstruktorů a metod nadřazené třídy, přepsání metod atd. Nyní se zaměříme na mateřskou loď hierarchie dědičnosti tříd Java, java.lang.Object
.
Studovat Objekt
a jeho metody vám pomohou lépe porozumět dědičnosti a jejímu fungování ve vašich programech Java. Seznámení s těmito metodami vám obecně pomůže lépe pochopit programy Java.
Objekt: Java je nadtřída
Objekt
je kořenová třída nebo konečná nadtřída všech ostatních tříd Java. Uloženo v java.lang
balík, Objekt
deklaruje následující metody, které zdědí všechny ostatní třídy:
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 nemohou.
Podíváme se na každou z těchto metod a na to, jak vám umožňují provádět speciální úkoly v kontextu vašich tříd Java. Nejprve se podívejme na základní pravidla a mechanismy pro Objekt
dědictví.
Obecné typy
Ve výše uvedeném seznamu jste si možná všimli getClass ()
, jehož Třída
návratový typ je příkladem a obecný typ. Obecným typům se budu věnovat v budoucím článku.
Rozšíření objektu: Příklad
Třída se může výslovně rozšířit Objekt
, jak je uvedeno v seznamu 1.
Výpis 1. Explicitně rozšiřující objekt
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 ()); }}
Protože můžete rozšířit maximálně jednu další třídu (připomeňme, že Java nepodporuje vícenásobné dědictví založené na třídách), nejste nuceni explicitně rozšířit Objekt
; jinak byste nemohli rozšířit žádnou jinou třídu. Proto byste prodloužili Objekt
implicitně, jak je uvedeno v seznamu 2.
Výpis 2. Implicitně rozšiřující 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 ()); }}
Zkompilujte výpis 1 nebo výpis 2 následujícím způsobem:
javac Employee.java
Spusťte výslednou aplikaci:
java zaměstnanec
Měli byste dodržovat následující výstup:
John Doe
Další informace o třídě: getClass ()
The getClass ()
metoda vrací běhovou třídu libovolného objektu, na kterém je volána. The běhová třída je reprezentován a Třída
objekt, který se nachází v java.lang
balík. Třída
je vstupním bodem do rozhraní Java Reflection API, o kterém se dozvíte, až se dostaneme k pokročilejším tématům v programování Java. Zatím víte, že aplikace Java používá Třída
a zbytek Java Reflection API se dozvíte o jeho vlastní struktuře.
Objekty třídy a statické synchronizované metody
Vrátil se Třída
objekt je objekt, který je uzamčen statická synchronizace
metody představované třídy; například, statická synchronizovaná void foo () {}
. (Synchronizaci Java představím v budoucím výukovém programu.)
Duplikování objektů: clone ()
The klon ()
metoda vytvoří a vrátí kopii objektu, na kterém je volána. Protože klon ()
návratový typ je Objekt
, odkaz na objekt klon ()
před přiřazením odkazu na proměnnou typu objektu musí být vráceny skutečnému typu objektu. Výpis 3 představuje aplikaci, která demonstruje klonování.
Výpis 3. Klonování objektu
třída CloneDemo implementuje Cloneable {int x; public static void main (String [] args) hodí CloneNotSupportedException {CloneDemo cd = new CloneDemo (); cd.x = 5; System.out.println ("cd.x =" + cd.x); CloneDemo cd2 = (CloneDemo) cd.clone (); System.out.println ("cd2.x =" + cd2.x); }}
Výpis 3 CloneDemo
třída implementuje Cloneable
rozhraní, které se nachází v java.lang
balík. Cloneable
je implementována třídou (prostřednictvím nářadí
klíčové slovo) Objekt
je klon ()
metoda z házení instance CloneNotSupportedException
třída (také nalezena v java.lang
).
CloneDemo
deklaruje singl int
- pojmenované pole instance X
a hlavní()
metoda, která tuto třídu procvičuje. hlavní()
je deklarováno s hodí
klauzule, která prochází 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
hodnota a volání 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
Přepsat klon ()
Předchozí příklad nepotřeboval přepsat klon ()
protože kód, který volá klon ()
se nachází v klonované třídě (CloneDemo
). Pokud volání na klon ()
byly umístěny v jiné třídě, pak byste museli přepsat klon ()
. Protože klon ()
je deklarováno chráněný
, obdržíte „klon má chráněný přístup v Object"zpráva, pokud jste ji před kompilací třídy nepotlačili. Výpis 4 představuje refaktorovaný výpis 3, který ukazuje 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 (); }} třída CloneDemo {public static void main (String [] args) hodí CloneNotSupportedException {Data data = new Data (); data.x = 5; System.out.println ("data.x =" + data.x); Data data2 = (Data) data.clone (); System.out.println ("data2.x =" + data2.x); }}
Výpis 4 deklaruje a Data
třída, jejíž instance mají být klonovány. Data
realizuje Cloneable
rozhraní, aby se zabránilo a CloneNotSupportedException
před hozením, když klon ()
metoda se nazývá. Poté prohlásí int
-založené pole instance X
a přepíše klon ()
metoda. The klon ()
metoda se provede super.clone ()
volat jeho nadtřídu (tj. Objekt
's) klon ()
metoda. Naléhavé klon ()
metoda identifikuje CloneNotSupportedException
v jeho hodí
doložka.
Výpis 4 také deklaruje a CloneDemo
třída, která: vytváří instanci Data
, inicializuje své pole instance, vypíše hodnotu pole instance, naklonuje Data
objekt a na výstupu zobrazí jeho hodnotu pole 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
Mělké klonování
Mělké klonování (také známý jako mělké kopírování) odkazuje na duplikování polí objektu bez duplikování jakýchkoli objektů, na které se odkazuje z referenčních polí daného objektu (pokud existují nějaká referenční pole). Výpisy 3 a 4 skutečně prokázaly mělké 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 ukazuje.
Výpis 5. Problém 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; }} třída CloneDemo {public static void main (String [] args) hodí CloneNotSupportedException {Employee e = new Employee ("John Doe", 49, new Address ("Denver")); System.out.println (e.getName () + ":" + e.getAge () + ":" + e.getAddress (). GetCity ()); Zaměstnanec e2 = (zaměstnanec) e.clone (); 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 ()); }}
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
Hluboké klonování
Hluboké klonování (také známý jako hluboké kopírování) odkazuje na duplikování polí objektu tak, aby byly duplikovány všechny odkazované objekty. Dále jsou duplikovány odkazované objekty odkazovaných objektů atd. Výpis 6 refaktorů Výpis 5 k prokázání hlubokého klonování.
Výpis 6. Hluboké klonování pole adresy
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 {Employee e = (Employee) super.clone (); e.adresa = (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 Object clone () {return new Address (new String (city)); } String getCity () {návratové město; } void setCity (String city) {this.city = city; }} třída CloneDemo {public static void main (String [] args) hodí CloneNotSupportedException {Employee e = new Employee ("John Doe", 49, new Address ("Denver")); System.out.println (e.getName () + ":" + e.getAge () + ":" + e.getAddress (). GetCity ()); Zaměstnanec e2 = (zaměstnanec) e.clone (); 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 ()); }}
Výpis 6 to ukazuje Zaměstnanec
je klon ()
metoda první volání super.clone ()
, který mělce kopíruje název
, stáří
, a adresa
pole. Pak zavolá klon ()
na adresa
pole pro vytvoření duplikátu odkazovaného Adresa
objekt. Adresa
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 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.