Ich muss einen tiefen Klon in einem meiner Objekte implementieren, der keine Oberklasse hat.
Was ist der beste Weg, um mit dem CloneNotSupportedException
von der Oberklasse (was ist Object
) geworfenen Scheck umzugehen ?
Ein Mitarbeiter hat mir geraten, folgendermaßen damit umzugehen:
@Override
public MyObject clone()
{
MyObject foo;
try
{
foo = (MyObject) super.clone();
}
catch (CloneNotSupportedException e)
{
throw new Error();
}
// Deep clone member fields here
return foo;
}
Dies scheint mir eine gute Lösung zu sein, aber ich wollte sie der StackOverflow-Community zur Verfügung stellen, um zu prüfen, ob ich weitere Erkenntnisse einschließen kann. Vielen Dank!
Cloneable
ist das Auslösen einerAssertionError
Ebene und nicht nur einer EbeneError
etwas ausdrucksvoller.Antworten:
Müssen Sie unbedingt verwenden
clone
? Die meisten Leute sind sich einig, dass Javaclone
kaputt ist.Josh Bloch über Design - Kopierkonstruktor versus Klonen
Weitere Informationen zu diesem Thema finden Sie in seinem Buch Effective Java 2nd Edition, Punkt 11: Mit Bedacht
clone
überschreiben . Er empfiehlt stattdessen die Verwendung eines Kopierkonstruktors oder einer Kopierfabrik.Er fuhr fort, Seiten von Seiten darüber zu schreiben, wie Sie implementieren sollten, wenn Sie das Gefühl haben, dass Sie es müssen
clone
. Aber er schloss damit:Der Schwerpunkt lag bei ihm, nicht bei mir.
Da Sie klargestellt haben, dass Sie keine andere Wahl haben, als zu implementieren
clone
, können Sie in diesem Fall Folgendes tun: Stellen Sie sicher, dassMyObject extends java.lang.Object implements java.lang.Cloneable
. Wenn dies der Fall ist, können Sie garantieren, dass Sie NIEMALS einen fangen werdenCloneNotSupportedException
. Werfen,AssertionError
wie einige vorgeschlagen haben, erscheint vernünftig, aber Sie können auch einen Kommentar hinzufügen, der erklärt, warum der catch-Block in diesem speziellen Fall niemals eingegeben wird .Alternativ können Sie, wie andere ebenfalls vorgeschlagen haben, möglicherweise implementieren,
clone
ohne aufzurufensuper.clone
.quelle
super.clone()
innerhalb ihrer Klonmethoden aufgerufen werden, muss eine Unterklasse im Allgemeinen nur überschreiben,clone()
wenn sie neue Felder hinzufügt, deren Inhalt geklont werden müsste. Wenn eine Oberklassenew
anstelle von verwendetsuper.clone()
, müssen alle Unterklassen überschreiben,clone()
ob sie neue Felder hinzufügen oder nicht.Manchmal ist es einfacher, einen Kopierkonstruktor zu implementieren:
Dies erspart Ihnen die Bearbeitung
CloneNotSupportedException
, arbeitet mitfinal
Feldern und Sie müssen sich keine Gedanken über den Typ machen, der zurückgegeben werden soll.quelle
Die Art und Weise, wie Ihr Code funktioniert, kommt der "kanonischen" Schreibweise ziemlich nahe. Ich würde aber einen
AssertionError
in den Haken werfen . Es signalisiert, dass diese Linie niemals erreicht werden sollte.quelle
Cloneable
im Allgemeinen eine kaputte Idee ist, wie in Effective Java erläutert. Das OP hat bereits zum Ausdruck gebracht, dass sie verwenden müssenCloneable
. Ich habe also keine Ahnung, wie ich meine Antwort verbessern könnte, außer sie vielleicht sofort zu löschen.Es gibt zwei Fälle, in denen der
CloneNotSupportedException
Wurf geworfen wird:Cloneable
(vorausgesetzt, das tatsächliche Klonen verschiebt sich schließlich auf die KlonmethodeObject
). Wenn die Klasse, in der Sie diese Methode schreiben, implementiert istCloneable
, wird dies niemals passieren (da Unterklassen sie entsprechend erben werden).Cloneable
.Der letztere Fall kann in Ihrer Klasse nicht auftreten (da Sie die Methode der Oberklasse im
try
Block direkt aufrufen , selbst wenn sie von einem Unterklassenaufruf aufgerufen wirdsuper.clone()
), und der erstere sollte dies nicht tun, da Ihre Klasse eindeutig implementieren sollteCloneable
.Grundsätzlich sollten Sie den Fehler auf jeden Fall protokollieren, aber in diesem speziellen Fall tritt er nur auf, wenn Sie die Definition Ihrer Klasse durcheinander bringen. Behandeln Sie es also wie eine überprüfte Version von
NullPointerException
(oder ähnlichem) - es wird niemals ausgelöst, wenn Ihr Code funktionsfähig ist.In anderen Situationen müssten Sie auf diese Eventualität vorbereitet sein - es gibt keine Garantie dafür, dass ein bestimmtes Objekt klonbar ist. Wenn Sie also die Ausnahme abfangen, sollten Sie abhängig von dieser Bedingung geeignete Maßnahmen ergreifen (fahren Sie mit dem vorhandenen Objekt fort und ergreifen Sie eine alternative Klonstrategie zB serialize-deserialize, werfen Sie ein,
IllegalParameterException
wenn Ihre Methode den Parameter durch klonbar benötigt, etc. etc.).Bearbeiten : Obwohl ich insgesamt darauf hinweisen sollte, dass es
clone()
wirklich schwierig ist, richtig zu implementieren, und es für Anrufer schwierig ist zu wissen, ob der Rückgabewert dem entspricht, was sie wollen, doppelt, wenn man tiefe oder flache Klone betrachtet. Es ist oft besser, das Ganze komplett zu vermeiden und einen anderen Mechanismus zu verwenden.quelle
super.clone()
.Verwenden Sie die Serialisierung , um tiefe Kopien zu erstellen. Dies ist nicht die schnellste Lösung, hängt jedoch nicht vom Typ ab.
quelle
Sie können geschützte Kopierkonstruktoren wie folgt implementieren:
quelle
clone()
das von zurückgegebene Objekt nur aufrufen,getMySecondMember()
wenn es über einepublic clone
Methode verfügt.So sehr die meisten Antworten hier gültig sind, muss ich sagen, dass Ihre Lösung auch so ist, wie es die tatsächlichen Java-API-Entwickler tun. (Entweder Josh Bloch oder Neal Gafter)
Hier ist ein Auszug aus der ArrayList-Klasse openJDK:
Wie Sie bemerkt haben und andere erwähnt haben,
CloneNotSupportedException
hat es fast keine Chance, geworfen zu werden, wenn Sie erklärt haben, dass Sie dieCloneable
Schnittstelle implementieren .Außerdem müssen Sie die Methode nicht überschreiben, wenn Sie in der überschriebenen Methode nichts Neues tun. Sie müssen es nur überschreiben, wenn Sie zusätzliche Vorgänge für das Objekt ausführen oder es öffentlich machen müssen.
Letztendlich ist es immer noch am besten, dies zu vermeiden und es auf eine andere Weise zu tun.
quelle
quelle
Nur weil die Java-Implementierung von Cloneable fehlerhaft ist, heißt das nicht, dass Sie keine eigene erstellen können.
Wenn OP der eigentliche Zweck war, einen tiefen Klon zu erstellen, denke ich, dass es möglich ist, eine Schnittstelle wie diese zu erstellen:
Verwenden Sie dann den zuvor erwähnten Prototyp-Konstruktor, um ihn zu implementieren:
und eine andere Klasse mit einem AClass-Objektfeld:
Auf diese Weise können Sie ein Objekt der Klasse BClass problemlos tief klonen, ohne @SuppressWarnings oder anderen kniffligen Code zu benötigen.
quelle