Metoda Clone() w Javie
Klonowanie obiektów odnosi się do tworzenia dokładnej kopii obiektu. Tworzy nową instancję klasy bieżącego obiektu i inicjuje wszystkie jej pola dokładnie zawartością odpowiednich pól tego obiektu.
Metody wykonywania klonowania obiektów w Javie
Istnieją 3 metody tworzenia klonowania obiektów w Javie, które wymieniono poniżej:
- Użycie operatora przypisania do utworzenia kopii zmiennej referencyjnej
- Tworzenie kopii za pomocą metody clone().
- Zastosowanie metody clone() – Deep Copy
1. Używanie operatora przypisania do tworzenia kopia zmienna referencyjna
W Javie nie ma operatora umożliwiającego utworzenie kopii obiektu. W przeciwieństwie do C++, w Javie, jeśli użyjemy operatora przypisania, utworzy on kopię zmiennej referencyjnej, a nie obiektu. Można to wyjaśnić na przykładzie. Poniższy program demonstruje to samo.
Poniżej realizacja powyższego tematu:
Jawa
// Java program to demonstrate that assignment operator> // only creates a new reference to same object> import> java.io.*;> > // A test class whose objects are cloned> class> Test {> > int> x, y;> > Test()> > {> > x => 10> ;> > y => 20> ;> > }> }> > // Driver Class> class> Main {> > public> static> void> main(String[] args)> > {> > Test ob1 => new> Test();> > > System.out.println(ob1.x +> ' '> + ob1.y);> > > // Creating a new reference variable ob2> > // pointing to same address as ob1> > Test ob2 = ob1;> > > // Any change made in ob2 will> > // be reflected in ob1> > ob2.x => 100> ;> > > System.out.println(ob1.x +> ' '> + ob1.y);> > System.out.println(ob2.x +> ' '> + ob2.y);> > }> }> |
Wyjście
10 20 100 20 100 20
2. Tworzenie kopii za pomocą metody clone().
Klasa, której obiekt ma zostać wykonana kopia, musi posiadać w sobie lub w jednej z klas nadrzędnych metodę publicznego klonowania.
- Każda klasa implementująca clone() powinna wywołać super.clone() w celu uzyskania odwołania do sklonowanego obiektu.
- Klasa musi także implementować interfejs java.lang.Cloneable, którego klon obiektu chcemy utworzyć, w przeciwnym razie zgłosi wyjątek CloneNotSupportedException, gdy na obiekcie tej klasy zostanie wywołana metoda klonowania.
Składnia:
protected Object clone() throws CloneNotSupportedException
i) Użycie metody clone() - Płytka kopia
Notatka – W poniższym przykładzie kodu metoda clone() tworzy zupełnie nowy obiekt z inną wartością hashCode, co oznacza, że znajduje się on w osobnej lokalizacji w pamięci. Ponieważ jednak obiekt testowy c znajduje się w teście2, typy pierwotne osiągnęły głęboką kopię, ale ten obiekt testowy c jest nadal współdzielony między t1 i t2. Aby temu zaradzić, jawnie wykonujemy głęboką kopię zmiennej obiektowej c, co zostanie omówione później.
Jawa
// A Java program to demonstrate> // shallow copy using clone()> import> java.util.ArrayList;> > // An object reference of this class is> // contained by Test2> class> Test {> > int> x, y;> }> > // Contains a reference of Test and> // implements clone with shallow copy.> class> Test2> implements> Cloneable {> > int> a;> > int> b;> > Test c => new> Test();> > public> Object clone()> throws> CloneNotSupportedException> > {> > return> super> .clone();> > }> }> > // Driver class> public> class> Main {> > public> static> void> main(String args[])> > throws> CloneNotSupportedException> > {> > Test2 t1 => new> Test2();> > t1.a => 10> ;> > t1.b => 20> ;> > t1.c.x => 30> ;> > t1.c.y => 40> ;> > > Test2 t2 = (Test2)t1.clone();> > > // Creating a copy of object t1> > // and passing it to t2> > t2.a => 100> ;> > > // Change in primitive type of t2 will> > // not be reflected in t1 field> > t2.c.x => 300> ;> > > // Change in object type field will be> > // reflected in both t2 and t1(shallow copy)> > System.out.println(t1.a +> ' '> + t1.b +> ' '> + t1.c.x> > +> ' '> + t1.c.y);> > System.out.println(t2.a +> ' '> + t2.b +> ' '> + t2.c.x> > +> ' '> + t2.c.y);> > }> }> |
Wyjście
10 20 300 40 100 20 300 40
W powyższym przykładzie t1.clone zwraca płytką kopię obiektu t1. Aby uzyskać głęboką kopię obiektu, po uzyskaniu kopii należy dokonać pewnych modyfikacji w metodzie klonowania.
ii) Zastosowanie metody clone() – Deep Copy
- Jeśli chcemy utworzyć głęboką kopię obiektu X i umieścić ją w nowym obiekcie Y, wówczas tworzona jest nowa kopia wszelkich pól obiektów, do których istnieją odniesienia, a odniesienia te umieszczane są w obiekcie Y. Oznacza to wszelkie zmiany dokonane w polach obiektów, do których istnieją odniesienia w obiekcie X lub Y zostaną odzwierciedlone tylko w tym obiekcie, a nie w drugim. W poniższym przykładzie tworzymy głęboką kopię obiektu.
- Głęboka kopia kopiuje wszystkie pola i tworzy kopie dynamicznie alokowanej pamięci, na którą wskazują pola. Głęboka kopia ma miejsce, gdy obiekt jest kopiowany wraz z obiektami, do których się odnosi.
Jawa
// A Java program to demonstrate> // deep copy using clone()> > // An object reference of this> // class is contained by Test2> class> Test {> > int> x, y;> }> > // Contains a reference of Test and> // implements clone with deep copy.> class> Test2> implements> Cloneable {> > int> a, b;> > > Test c => new> Test();> > > public> Object clone()> throws> CloneNotSupportedException> > {> > // Assign the shallow copy to> > // new reference variable t> > Test2 t = (Test2)> super> .clone();> > > // Creating a deep copy for c> > t.c => new> Test();> > t.c.x = c.x;> > t.c.y = c.y;> > > // Create a new object for the field c> > // and assign it to shallow copy obtained,> > // to make it a deep copy> > return> t;> > }> }> > public> class> Main {> > public> static> void> main(String args[])> > throws> CloneNotSupportedException> > {> > Test2 t1 => new> Test2();> > t1.a => 10> ;> > t1.b => 20> ;> > t1.c.x => 30> ;> > t1.c.y => 40> ;> > > Test2 t3 = (Test2)t1.clone();> > t3.a => 100> ;> > > // Change in primitive type of t2 will> > // not be reflected in t1 field> > t3.c.x => 300> ;> > > // Change in object type field of t2 will> > // not be reflected in t1(deep copy)> > System.out.println(t1.a +> ' '> + t1.b +> ' '> + t1.c.x> > +> ' '> + t1.c.y);> > System.out.println(t3.a +> ' '> + t3.b +> ' '> + t3.c.x> > +> ' '> + t3.c.y);> > }> }> |
Wyjście
10 20 30 40 100 20 300 40
W powyższym przykładzie widzimy, że do klasy Test został przypisany nowy obiekt w celu skopiowania obiektu, który zostanie zwrócony do metody clone. Dzięki temu t3 uzyska głęboką kopię obiektu t1. Zatem wszelkie zmiany wprowadzone w polach obiektu „c” do czasu t3 nie zostaną odzwierciedlone w t1.
Głęboka kopia kontra płytka kopia
Istnieją pewne różnice między używaniem funkcji clone() jako głębokiej kopii a płytkiej kopii, jak wspomniano poniżej:
- Płytka kopia to metoda kopiowania obiektu, stosowana domyślnie podczas klonowania. W tej metodzie pola starego obiektu X są kopiowane do nowego obiektu Y. Podczas kopiowania pola typu obiektu odwołanie jest kopiowane do Y, czyli obiekt Y będzie wskazywał to samo miejsce, które wskazał X. Jeżeli wartość pola jest typem pierwotnym, kopiuje wartość typu pierwotnego.
- Dlatego wszelkie zmiany dokonane w obiektach odniesienia w obiekcie X lub Y zostaną odzwierciedlone w innych obiektach.
Płytkie kopie są tanie i proste w wykonaniu. W powyższym przykładzie utworzyliśmy płytką kopię the obiekt.
Po co używać metody klonowania() lub Zalety metody klonowania
- Jeśli użyjemy operatora przypisania do przypisania odniesienia do obiektu do innej zmiennej odniesienia, wówczas wskaże on tę samą lokalizację adresową starego obiektu i nie zostanie utworzona żadna nowa kopia obiektu. Dzięki temu wszelkie zmiany w zmiennej referencyjnej zostaną odzwierciedlone w oryginalnym obiekcie.
- Jeśli użyjemy konstruktora kopiującego, musimy jawnie skopiować wszystkie dane, tj. musimy jawnie ponownie przypisać wszystkie pola klasy w konstruktorze. Ale w metodzie klonowania praca polegająca na utworzeniu nowej kopii jest wykonywana przez samą metodę. Aby uniknąć dodatkowego przetwarzania, używamy klonowania obiektów.