Szukałem kilku tutoriali wyjaśniających o Javie Cloneable
, ale nie otrzymałem żadnych dobrych linków, a Stack Overflow i tak staje się bardziej oczywistym wyborem.
Chciałbym wiedzieć, co następuje:
Cloneable
oznacza, że możemy mieć klon lub kopię obiektów, implementującCloneable
interfejs. Jakie są zalety i wady takiego działania?- Jak przebiega klonowanie rekurencyjne, jeśli obiekt jest obiektem złożonym?
Odpowiedzi:
Pierwszą rzeczą, o której powinieneś wiedzieć,
Cloneable
jest to, że nie używaj go.Bardzo trudno jest
Cloneable
poprawnie wdrożyć klonowanie , a wysiłek nie jest tego wart.Zamiast tego użyj innych opcji, takich jak apache-commons
SerializationUtils
(głęboki klon) lubBeanUtils
(płytki-klon) lub po prostu użyj konstruktora kopiującego.Spójrz tutaj opinie Josha Blocha na temat klonowania za pomocą
Cloneable
, co wyjaśnia wiele wad tego podejścia. ( Joshua Bloch był pracownikiem firmy Sun i kierował rozwojem wielu funkcji języka Java).źródło
static
metody w interfejsach, więc po prostu podajstatic WhatEverTheInterface copy(WhatEverTheInterface initial)
? ale zastanawiam się, co to daje, skoro kopiujesz pola z obiektu podczas klonowania, ale interfejs definiuje tylko metody. chcesz wyjaśnić?Sam Cloneable jest niestety tylko interfejsem znacznika, to znaczy: nie definiuje metody clone ().
To, co robi, to zmiana zachowania chronionej metody Object.clone (), która wyrzuci wyjątek CloneNotSupportedException dla klas, które nie implementują Cloneable, i wykona płytką kopię dla elementów członkowskich dla klas, które to robią.
Nawet jeśli jest to zachowanie, którego szukasz, nadal musisz zaimplementować własną metodę clone (), aby je upublicznić.
Podczas implementacji własnego clone (), chodzi o to, aby zacząć od obiektu utworzonego przez super.clone (), który na pewno będzie odpowiedniej klasy, a następnie wykonać dowolną dodatkową populację pól na wypadek, gdyby płytka kopia nie była tym, czym chcesz. Wywołanie konstruktora z funkcji clone () byłoby problematyczne, ponieważ spowodowałoby zerwanie dziedziczenia w przypadku, gdy podklasa chce dodać swoją własną, możliwą do klonowania logikę; jeśli wywoła super.clone (), w tym przypadku otrzyma obiekt niewłaściwej klasy.
Takie podejście omija jednak logikę, która może być zdefiniowana w twoich konstruktorach, co może być potencjalnie problematyczne.
Innym problemem jest to, że wszystkie podklasy, które zapomną nadpisać clone (), automatycznie odziedziczą domyślną płytką kopię, co prawdopodobnie nie jest tym, czego chcesz w przypadku stanu zmiennego (który będzie teraz współdzielony między źródłem a kopią).
Większość programistów nie używa Cloneable z tych powodów i zamiast tego po prostu implementuje konstruktor kopiujący.
Aby uzyskać więcej informacji i potencjalnych pułapek Cloneable, gorąco polecam książkę Effective Java autorstwa Joshua Blocha
źródło
Więc rozsądnie używaj Cloneable. Nie daje to wystarczających korzyści w porównaniu z wysiłkiem, jaki musisz włożyć, aby zrobić wszystko dobrze.
źródło
Klonowanie to podstawowy paradygmat programowania. Fakt, że Java mogła źle zaimplementować go pod wieloma względami, wcale nie zmniejsza potrzeby klonowania. I łatwo jest wdrożyć klonowanie, które będzie działać tak, jak chcesz, płytko, głęboko, mieszane, cokolwiek. Możesz nawet użyć nazwy clone dla funkcji i nie implementować Cloneable, jeśli chcesz.
Załóżmy, że mam klasy A, B i C, gdzie B i C pochodzą od A. Jeśli mam listę obiektów typu A w następujący sposób:
Ta lista może zawierać obiekty typu A, B lub C. Nie wiesz, jakiego typu są te obiekty. Nie możesz więc skopiować listy w ten sposób:
Jeśli obiekt jest rzeczywiście typu B lub C, nie otrzymasz właściwej kopii. A co, jeśli A jest abstrakcyjne? Niektórzy ludzie zasugerowali to:
To bardzo, bardzo zły pomysł. Co się stanie, jeśli dodasz nowy typ pochodny? Co jeśli B lub C znajdują się w innym pakiecie i nie masz do nich dostępu w tej klasie?
Co chciałbyś zrobić, to:
Wiele osób wskazało, dlaczego podstawowa implementacja klona w Javie jest problematyczna. Ale można to łatwo pokonać w ten sposób:
W klasie A:
W klasie B:
W klasie C:
Nie implementuję Cloneable, po prostu używam tej samej nazwy funkcji. Jeśli ci się to nie podoba, nazwij to inaczej.
źródło
A) Nie ma wielu zalet clone w porównaniu z konstruktorem kopiującym. Prawdopodobnie największą z nich jest możliwość stworzenia nowego obiektu o dokładnie tym samym typie dynamicznym (przy założeniu, że zadeklarowany typ jest klonowalny i ma publiczną metodę klonowania).
B) Domyślny klon tworzy płytką kopię i pozostanie płytką kopią, chyba że implementacja klonu to zmieni. Może to być trudne, zwłaszcza jeśli twoja klasa ma ostatnie pola
Bozho ma rację, klon może być trudny do uzyskania. Konstruktor kopii / fabryka będzie spełniać większość potrzeb.
źródło
Jakie są wady Cloneable?
Klonowanie jest bardzo niebezpieczne, jeśli obiekt który kopiujesz ma kompozycję, musisz pomyśleć o poniżej możliwym efekcie ubocznym w tym przypadku, ponieważ klon tworzy płytką kopię:
Powiedzmy, że masz jeden obiekt do obsługi manipulacji związanych z db. Powiedzmy, że obiekt ma
Connection
obiekt jako jedną z właściwości.Więc gdy ktoś tworzy klona
originalObject
, tworzonego obiektu, powiedzmycloneObject
. TutajoriginalObject
icloneObject
trzymaj to samo odniesienie dlaConnection
obiektu.Powiedzmy, że
originalObject
zamykaConnection
obiekt, więc terazcloneObject
nie będzie działać, ponieważconnection
obiekt był między nimi współdzielony i został aktywnie zamknięty przezoriginalObject
.Podobny problem może wystąpić, jeśli powiedzmy, że chcesz sklonować obiekt, który ma IOStream jako właściwość.
Jak przebiega klonowanie rekurencyjne, jeśli obiekt jest obiektem złożonym?
Cloneable wykonuje płytką kopię. Oznacza to, że dane oryginalnego obiektu i obiektu sklonowanego będą wskazywać na to samo odniesienie / pamięć. w przeciwieństwie do głębokiej kopii, dane z pamięci obiektu oryginalnego są kopiowane do pamięci obiektu klonowanego.
źródło
Cloneable
nie wykonuje kopii,Object.clone
robi. "Dane z pamięci oryginalnego obiektu są kopiowane do pamięci klonowanego obiektu" to właśnie toObject.clone
robi. Aby opisać głębokie kopiowanie, musisz porozmawiać o pamięci obiektów, do których istnieją odniesienia.