Antworten:
Die Tatsache, dass der Klon geschützt ist, ist äußerst zweifelhaft - ebenso wie die Tatsache, dass die clone
Methode nicht in der Cloneable
Schnittstelle deklariert ist .
Dies macht die Methode für das Erstellen von Kopien von Daten ziemlich nutzlos, da Sie nicht sagen können :
if(a instanceof Cloneable) {
copy = ((Cloneable) a).clone();
}
Ich denke, dass das Design von Cloneable
jetzt weitgehend als Fehler angesehen wird (Zitat unten). Normalerweise möchte ich in der Lage sein, Implementierungen einer Schnittstelle vorzunehmen,Cloneable
aber nicht unbedingt die SchnittstelleCloneable
(ähnlich der Verwendung von Serializable
). Dies kann nicht ohne Reflexion geschehen:
ISomething i = ...
if (i instanceof Cloneable) {
//DAMN! I Need to know about ISomethingImpl! Unless...
copy = (ISomething) i.getClass().getMethod("clone").invoke(i);
}
Zitat aus Josh Blochs effektivem Java :
"Die klonbare Schnittstelle war als Mixin-Schnittstelle für Objekte gedacht, um anzukündigen, dass sie das Klonen erlauben. Leider erfüllt sie diesen Zweck nicht ... Dies ist eine sehr atypische Verwendung von Schnittstellen und keine zu emulierende ... Damit die Implementierung der Schnittstelle Auswirkungen auf eine Klasse hat, müssen sie und alle ihre Oberklassen einem ziemlich komplexen, nicht durchsetzbaren und weitgehend undokumentierten Protokoll folgen. "
Serializable
- es liegt an den Implementierungen, zu entscheiden, ob sie implementiert werden sollen Serializable
. Ich habe dies erweitert auf Cloneable
- es ist nicht etwas, das eine Schnittstelle erweitern sollte -, aber eine Implementierung einer Schnittstelle ist frei zu sein Cloneable
. Das Problem ist, wenn Sie einen Parameter vom Schnittstellentyp haben, fragen Sie ihn, ob er klonbar ist. aber dann kann man es nicht wirklich klonen!
Die klonbare Schnittstelle ist nur eine Markierung, die besagt, dass die Klasse das Klonen unterstützen kann. Die Methode ist geschützt, da Sie sie nicht für ein Objekt aufrufen sollten, sondern sie als öffentlich überschreiben können (und sollten).
Von der Sonne:
In der Klasse Object wird die Methode clone () als geschützt deklariert. Wenn Sie nur Cloneable implementieren, können nur Unterklassen und Mitglieder desselben Pakets clone () für das Objekt aufrufen. Damit eine Klasse in einem Paket auf die clone () -Methode zugreifen kann, müssen Sie sie überschreiben und als öffentlich deklarieren, wie unten beschrieben. (Wenn Sie eine Methode überschreiben, können Sie sie weniger privat, aber nicht privater machen. Hier wird die geschützte clone () -Methode in Object als öffentliche Methode überschrieben.)
Set
clone
ist geschützt, weil es etwas ist, das überschrieben werden sollte, damit es spezifisch für die aktuelle Klasse ist. Es wäre zwar möglich, eine öffentliche clone
Methode zu erstellen , die jedes Objekt klonen würde, dies wäre jedoch nicht so gut wie eine Methode, die speziell für die Klasse geschrieben wurde, die sie benötigt.
Die Clone-Methode kann nicht direkt für ein Objekt verwendet werden, weshalb sie von der Unterklasse überschrieben werden soll.
Natürlich könnte es öffentlich sein und nur eine entsprechende Ausnahme auslösen, wenn das Klonen nicht möglich ist, aber ich denke, das wäre irreführend.
Die Art und Weise, wie der Klon jetzt implementiert wird, lässt Sie darüber nachdenken, warum Sie den Klon verwenden möchten und wie Ihr Objekt geklont werden soll.
Es ist geschützt, da die Standardimplementierung eine flache Kopie aller Felder (einschließlich privater Felder) in Mitgliedsform erstellt und den Konstruktor umgeht . Dies ist nicht etwas, für das ein Objekt in erster Linie ausgelegt sein könnte (z. B. kann es die erstellten Objektinstanzen in einer gemeinsam genutzten Liste oder Ähnlichem verfolgen).
Aus dem gleichen Grund wird die Standardimplementierung von clone()
ausgelöst, wenn das aufgerufene Objekt nicht implementiert wird Cloneable
. Es ist eine potenziell unsichere Operation mit weitreichenden Konsequenzen, und daher muss sich der Autor der Klasse ausdrücklich anmelden.
Aus dem Javadoc von klonbar.
* 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.
Sie könnten also Klon für jedes Objekt aufrufen, aber dies würde Ihnen die meiste Zeit nicht die gewünschten Ergebnisse oder eine Ausnahme geben. Wird aber nur empfohlen, wenn Sie klonbar implementieren.
IMHO ist es so einfach:
#clone
darf nicht für nicht klonbare Objekte aufgerufen werden, daher wird es nicht veröffentlicht#clone
muss von Unterklassen ob aufgerufen werden Object
, die Cloneable implementieren, um die flache Kopie der richtigen Klasse zu erhaltenWas ist der richtige Bereich für Methoden, die von Unterklassen aufgerufen werden sollen, aber nicht von anderen Klassen?
Es ist protected
.
Klassen, die Cloneable
natürlich implementieren , machen diese Methode öffentlich, damit sie von anderen Klassen aufgerufen werden kann.
Die Clone () -Methode verfügt über eine interne Prüfung 'Instanz von Cloneable or not'. Auf diese Weise könnte das Java-Team die missbräuchliche Verwendung der clone () -Methode einschränken. Die clone () -Methode ist geschützt, dh nur für Unterklassen zugänglich. Da object die übergeordnete Klasse aller Unterklassen ist, kann die Clone () -Methode von allen infact-Klassen verwendet werden, wenn die obige Prüfung der 'Instanz von Cloneable' nicht vorliegt. Dies ist der Grund, warum das Java-Team möglicherweise daran gedacht hat, die missbräuchliche Verwendung von clone () durch die Überprüfung der clone () -Methode "Ist es eine Instanz von Cloneable" einzuschränken?
Daher kann jede klonbare Klasse die clone () -Methode der Object-Klasse verwenden.
Da es geschützt ist, steht es nur den Unterklassen zur Verfügung, die eine klonbare Schnittstelle implementieren. Wenn wir es öffentlich machen wollen, muss diese Methode von der Unterklasse mit ihrer eigenen Implementierung überschrieben werden.
Ja, das gleiche Problem, das ich getroffen habe. Aber ich löse es, indem ich diesen Code implementiere
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;
}
}
Genau wie vorher hat jemand gesagt.
Nun, auch die Sun-Entwickler sind nur Menschen, und sie haben tatsächlich einen großen Fehler gemacht, um die Klonmethode als geschützt zu implementieren, den gleichen Fehler wie sie eine nicht funktionierende Klonmethode in ArrayList implementiert haben! Im Allgemeinen gibt es sogar ein viel tieferes Missverständnis selbst erfahrener Java-Programmierer über die Klonmethode.
Ich habe jedoch kürzlich eine schnelle und einfache Lösung gefunden, um jedes Objekt mit seinem gesamten Inhalt zu kopieren, unabhängig davon, wie es erstellt wurde und was es enthält. Meine Antwort finden Sie hier: Fehler bei der Verwendung von Object.clone ()
Auch hier zeigt das Java JDK-Framework brillantes Denken:
Die klonbare Schnittstelle enthält keinen "öffentlichen T-Klon ()". Methode, weil sie sich eher wie ein Attribut verhält (z. B. serialisierbar), mit dem eine Instanz geklont werden kann.
An diesem Design ist nichts auszusetzen, weil:
Object.clone () macht mit Ihrer benutzerdefinierten Klasse nicht das, was Sie wollen.
Wenn Myclass Cloneable implementiert =>, überschreiben Sie clone () mit "public MyClass clone ()".
Wenn MyInterface Cloneable erweitert und einige MyClasses MyInterface implementieren: Definieren Sie einfach "public MyInterface clone ();" In der Schnittstelle und bei jeder Methode, die MyInterface-Objekte verwendet, können diese unabhängig von ihrer MyClass-Klasse geklont werden.