Odpowiedzi:
Fakt, że klon jest chroniony, jest niezwykle wątpliwy - podobnie jak fakt, że clone
metoda nie jest zadeklarowana w Cloneable
interfejsie.
To sprawia, że metoda jest całkiem bezużyteczna do kopiowania danych, ponieważ nie można powiedzieć :
if(a instanceof Cloneable) {
copy = ((Cloneable) a).clone();
}
Myślę, że projekt Cloneable
jest obecnie w dużej mierze uważany za błąd (cytat poniżej). Normalnie chciałbym mieć możliwość tworzenia implementacji interfejsu, Cloneable
ale niekoniecznie tworzenia interfejsuCloneable
(podobnie jak w przypadku Serializable
). Nie można tego zrobić bez refleksji:
ISomething i = ...
if (i instanceof Cloneable) {
//DAMN! I Need to know about ISomethingImpl! Unless...
copy = (ISomething) i.getClass().getMethod("clone").invoke(i);
}
Cytat z Effective Java Josha Blocha :
„Interfejs Cloneable został pomyślany jako interfejs mieszany dla obiektów w celu ogłaszania, że zezwalają na klonowanie. Niestety nie spełnia on tego celu ... Jest to wysoce nietypowe użycie interfejsów i nie należy go emulować ... Aby zaimplementowanie interfejsu miało jakikolwiek wpływ na klasę, on i wszystkie jego nadklasy muszą być zgodne z dość złożonym, niewykonalnym iw dużej mierze nieudokumentowanym protokołem. "
Serializable
- to do implementacji zdecydować, czy wdrożyć Serializable
. Rozszerzyłem to na Cloneable
- nie jest to coś, co interfejs powinien rozszerzać - ale implementacja interfejsu jest wolna Cloneable
. Problem w tym, że jeśli masz parametr typu interfejsu, pytasz go, czy można go sklonować; ale wtedy nie możesz tego sklonować!
Interfejs Clonable to tylko wskaźnik mówiący, że klasa może obsługiwać klon. Metoda jest chroniona, ponieważ nie powinieneś wywoływać jej na obiekcie, możesz (i powinieneś) nadpisać ją jako publiczną.
Od słońca:
W klasie Object metoda clone () jest deklarowana jako chroniona. Jeśli wszystko, co zrobisz, to zaimplementowanie Cloneable, tylko podklasy i elementy tego samego pakietu będą mogły wywołać clone () na obiekcie. Aby umożliwić dowolnej klasie w dowolnym pakiecie dostęp do metody clone (), musisz ją przesłonić i zadeklarować jako publiczną, tak jak pokazano poniżej. (Gdy nadpisujesz metodę, możesz uczynić ją mniej prywatną, ale nie bardziej prywatną. W tym przypadku chroniona metoda clone () w Object jest zastępowana jako metoda publiczna).
Set
clone
jest chroniony, ponieważ jest to coś, co powinno zostać zastąpione, aby było specyficzne dla bieżącej klasy. Chociaż byłoby możliwe utworzenie clone
metody publicznej , która w ogóle sklonowałaby dowolny obiekt, nie byłaby tak dobra, jak metoda napisana specjalnie dla klasy, która tego potrzebuje.
Metoda Clone nie może być używana bezpośrednio na żadnym obiekcie, dlatego jest przeznaczona do zastąpienia przez podklasę.
Oczywiście mogłoby to być publiczne i po prostu zgłosić odpowiedni wyjątek, gdy klonowanie nie jest możliwe, ale myślę, że byłoby to mylące.
Sposób, w jaki klon jest teraz zaimplementowany, sprawia, że myślisz o tym, dlaczego chcesz użyć klonowania i jak chcesz, aby twój obiekt był klonowany.
Jest chroniony, ponieważ domyślna implementacja tworzy płytką kopię składową wszystkich pól (w tym prywatnych), omijając konstruktora . Nie jest to coś, do czego obiekt mógłby zostać zaprojektowany w pierwszej kolejności (na przykład może śledzić instancje utworzonych obiektów na liście współdzielonej lub coś podobnego).
Z tego samego powodu domyślna implementacja clone()
spowoduje zgłoszenie, jeśli wywoływany obiekt nie jest implementowany Cloneable
. Jest to potencjalnie niebezpieczna operacja o dalekosiężnych konsekwencjach, dlatego autor klasy musi wyraźnie wyrazić zgodę.
Z javadoc pliku cloneable.
* By convention, classes that implement this interface (cloneable) should override
* <tt>Object.clone</tt> (which is protected) with a public method.
* See {@link java.lang.Object#clone()} for details on overriding this
* method.
* Note that this interface does <i>not</i> contain the <tt>clone</tt> method.
* Therefore, it is not possible to clone an object merely by virtue of the
* fact that it implements this interface. Even if the clone method is invoked
* reflectively, there is no guarantee that it will succeed.
Możesz więc wywołać clone na każdym obiekcie, ale przez większość czasu nie da ci to pożądanych wyników ani wyjątku. Ale jest zalecane tylko wtedy, gdy zaimplementujesz cloneable.
IMHO to takie proste:
#clone
nie mogą być wywoływane na obiektach nie dających się klonować, dlatego nie są upubliczniane#clone
musi być wywoływana przez podklasy ob, Object
które implementują Cloneable, aby uzyskać płytką kopię odpowiedniej klasyJaki jest właściwy zakres dla metod, które mają być wywoływane przez podklasy, ale nie przez inne klasy?
To jest protected
.
Klasy implementujące, Cloneable
oczywiście, upublicznią tę metodę, aby można ją było wywołać z innych klas.
Metoda Clone () ma wewnętrzną kontrolę „instancja klonowalna czy nie”. W ten sposób zespół Java może sądzić, że ograniczy niewłaściwe użycie metody clone (). Metoda clone () jest chroniona, tj. Dostęp do niej mają tylko podklasy. Ponieważ obiekt jest klasą nadrzędną wszystkich podklas, więc metoda Clone () może być używana przez wszystkie klasy, jeśli nie mamy powyższego sprawdzenia 'instancji Cloneable'. To jest powód, dla którego zespół Java mógł pomyśleć o ograniczeniu niewłaściwego użycia funkcji clone () poprzez sprawdzenie w metodzie clone () „czy jest to instancja Cloneable”.
Stąd wszystkie klasy implementujące cloneable mogą używać metody clone () klasy Object.
Ponieważ jest chroniony, jest dostępny tylko dla tych podklas, które implementują klonowalny interfejs. Jeśli chcemy, aby była publiczna, ta metoda musi zostać zastąpiona przez podklasę z jej własną implementacją.
Tak, ten sam problem, z którym się spotkałem. Ale rozwiązuję to, implementując ten kod
public class Side implements Cloneable {
public Side clone() {
Side side = null;
try {
side = (Side) super.clone();
} catch (CloneNotSupportedException e) {
System.err.println(e);
}
return side;
}
}
Tak jak wcześniej ktoś powiedział.
Cóż, także programiści słońca są tylko ludźmi i rzeczywiście popełnili ogromny błąd, implementując metodę klonowania jako chronioną, ten sam błąd, który zaimplementowali niedziałającą metodę klonowania w ArrayList! Tak więc, ogólnie rzecz biorąc, nawet doświadczeni programiści Javy nie rozumieją metody klonowania.
Jednak ostatnio znalazłem szybkie i łatwe rozwiązanie do kopiowania dowolnego obiektu z całą zawartością, bez względu na to, jak jest zbudowany i co zawiera, zobacz moją odpowiedź tutaj: Błąd w używaniu Object.clone ()
Ponownie, framework Java JDK pokazuje genialne myślenie:
Interfejs klonowalny nie zawiera "public T clone ();" metoda, ponieważ działa bardziej jak atrybut (np. serializowalny), który umożliwia sklonowanie instancji.
Nie ma nic złego w tym projekcie, ponieważ:
Object.clone () nie zrobi tego, co chcesz z klasą zdefiniowaną przez użytkownika.
Jeśli masz implementację Myclass Cloneable => nadpisujesz clone () przez "public MyClass clone ()"
Jeśli masz MyInterface rozszerza Cloneable i niektóre MyClasses implementujące MyInterface: po prostu zdefiniuj "public MyInterface clone ();" w interfejsie i każda metoda używająca obiektów MyInterface będzie mogła je sklonować, niezależnie od ich klasy MyClass.