Programování

Konečná nadtřída, část 1

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áletoString () metoda může být přepsána, zatímco finálePoč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 Objektje 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 Xa přepíše klon () metoda. Tato metoda se spustí super.clone () vyvolat své nadtřídy (Objektv 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.

CloneDemoje 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ěstnanecpř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ěstnanecje 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 jen Objektje klon () metoda vyžaduje, aby třída implementovala toto rozhraní a toto klon () metoda není volána.
  • Naléhavé klon () metoda nehází CloneNotSupportedException. Tato zaškrtnutá výjimka je vyvolána pouze z Objektje klon () 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.
  • Objektje klon () metoda se nevolá (není super.clone () volání), protože pro Adresa 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.

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