2010-03-11 5 views
115

Clone-Methode vs Kopie Konstruktor in Java. Welche ist die richtige Lösung? Wo soll jeder Fall verwendet werden?Clone() vs Copy-Konstruktor - was in Java empfohlen wird

+6

http://StackOverflow.com/Questions/1106102/Clone-VS-Copy-Constructor-VS-Factory-Method –

+3

Vermeiden Sie "Klon" * um jeden Preis * und gehen Sie für Ihre eigene Kopierlösung. – dimitarvp

+0

Kopieren Konstruktoren sind besser als Object.clone() weil sie Erzwingen Sie uns nicht, irgendeine Schnittstelle zu implementieren oder irgendeine Ausnahme zu werfen, aber wir können es sicher tun, wenn es erforderlich ist Benötigen Sie keine Umwandlungen, Erfordern Sie uns nicht von einem unbekannten Objekt abhängen Erstellungsmechanismus, Erfordern keine Elternklasse, um irgendeinen Vertrag zu befolgen oder irgendetwas zu implementieren, Erlauben Sie uns, letzte Felder zu modifizieren, erlauben Sie uns, die vollständige Kontrolle über die Objekterstellung zu haben, können wir unsere Initialisierungslogik darin schreiben. Lesen Sie mehr https://programmingmitra.blogspot.in/2017/01/Java-cloning-copy-constructor-versus-Object-clone-or-cloning.html –

Antwort

90

Klon ist kaputt, also benutzen Sie es nicht.

die Clone-Methode der Object-Klasse ist eine etwas magische Methode, die tut, was keine reine Java-Methode jemals tun konnte: Es eine identische Kopie von sein Objekt erzeugt. Es war in der Primordial Object Superklasse seit der Beta-Release-Tage der Java Compiler *; und es, wie alle alten Magie, erfordert die entsprechende incantation den Zauber von unerwartet zu verhindern backfiring

Bevorzugen Sie eine Methode, die kopiert das Objekt

Foo copyFoo (Foo foo){ 
    Foo f = new Foo(); 
    //for all properties in FOo 
    f.set(foo.get()); 
    return f; 
} 

Lesen Sie mehr http://adtmag.com/articles/2000/01/18/effective-javaeffective-cloning.aspx

+18

Um, Klon ist nicht gebrochen. Warum denkst du ist es? Wenn es ist, weil es nicht funktioniert, wenn Sie es nicht überschreiben - nun, das ist sein Vertrag. – Bozho

+23

@Bozho, lesen _Effective Java 2nd Edition_, erklärte Bloch es ziemlich gut. Doug Lea benutzt 'klon()' nicht mehr, außer um Arrays zu klonen (http://www.artima.com/intv/bloch13.html). – polygenelubricants

+1

Ich verstehe nicht wirklich, warum das Klonen nicht einfacher sein kann. Ist das eine Wahl? oder dahinter stehen wirklich harte Probleme? – LB40

47

Bedenken Sie, dass clone() nicht out of the box funktioniert. Sie müssen Cloneable implementieren und die clone()-Methode außer Kraft setzen, die in public macht.

Es gibt ein paar Alternativen, die bevorzugt sind (da die clone() Methode hat viele Design-Fragen, wie in anderen Antworten angegeben), und die Kopie-Konstruktor würde erfordern Handarbeit:

+1

Wie funktioniert diese tiefe Klon-Bibliothek an einem Objekt? Ich rieche Code, der wahrscheinlich mit Reflexion gespickt ist – Cruncher

+0

ja, eine Menge Reflexion :) – Bozho

+0

welche von diesen kopiert keine Referenzen und kopieren nach Werten? BeanUtils.cloneBean (Bean) kopiert Referenzen, aber ich verwende eine Android-Version (android-java-air-bridge.jar) nicht original Apache-Version. –

3

Siehe auch umzusetzen : How to properly override clone method?. Klonen ist in Java gebrochen, es ist so hart, um es richtig zu machen, und selbst wenn es tut bietet nicht wirklich viel, so ist es nicht wirklich die Mühe wert.

+0

Es ist viel einfacher, mit einer 'finalen' Klasse, die von' java.lang.Object' erbt, richtig zu kommen. Es ist schwierig, wenn die Klasse veränderbare Datenstrukturen enthält (und somit eine Deepcopy erfordert), aber die gleiche Herausforderung würde sich auch in einem Kopierkonstruktor ergeben. – IceArdor

18

Beachten Sie, dass der Kopierkonstruktor den Klassentyp auf den des Kopierkonstruktors beschränkt. Betrachten Sie das Beispiel:

// Need to clone person, which is type Person 
Person clone = new Person(person); 

Das funktioniert nicht, wenn person eine Unterklasse von Person sein könnte (oder wenn Person ist eine Schnittstelle). Das ist der springende Punkt von Klon, dass es den richtigen Typ zur Laufzeit dynamisch klonen kann (vorausgesetzt, Klon ist korrekt implementiert).

Person clone = (Person)person.clone(); 

oder

Person clone = (Person)SomeCloneUtil.clone(person); // See Bozho's answer 

Jetzt können person jede Art von Person unter der Annahme, dass clone richtig umgesetzt wird.

+0

Es ist bedauerlich, dass jemand einmal vorgeschlagen hat, dass eine korrekte Implementierung des Klons "new" statt "super.clone()" beinhalten sollte, da das richtige Verhalten für 'clone' darin besteht, 'super.clone()' aufzurufen, wenn diese Methode selbst verwendet wird ruft 'super.clone()' auf (oder ist der integrierte Memberwise-Klon für ein Objekt); Wenn 'super.clone()' schließlich 'new' aufruft, ist das einzige, nicht völlig durchgebrochene Verhalten für' clone() ',' 'new'' selbst zu nennen, aber dann muss jede untergeordnete Klasse 'clone()' überschreiben Machen Sie ebenfalls, ob die Kindklasse sonst 'clone()' überschreiben müsste. – supercat

+0

Die Frage "tief gegen flach" erscheint mir in den meisten Fällen nicht mehrdeutig. Eine 'SomeCollection ' existiert, um die * Identitäten * von Dingen vom Typ' T' zu enthalten, und das Aufrufen von 'clone()' auf einer sollte eine neue Instanz desselben Typs ergeben, die vom Original losgelöst ist, aber Verweise darauf enthält 'T's.Nichts, was mit dem Original oder dem Klon gemacht werden kann, sollte die * Identitäten * der Objekte beeinflussen, die in dem anderen gespeichert sind. Ich verstehe wirklich nicht, was die Verwirrung ist. – supercat

30

clone() wurde mit mehreren Fehlern erstellt (siehe this question), also vermeiden Sie es am besten.

Von Effective Java 2nd Edition, Punkt 11: Überschreiben von Klon umsichtig

alle Probleme im Zusammenhang mit klonbar Gegeben, ist es sicher zu sagen, dass andere Schnittstellen nicht verlängern sollte, und dass für Vererbung entworfen Klassen (Artikel 17) sollte es nicht umsetzen. Wegen seine vielen Mängel, wählen einige Experten Programmierer einfach nie überschreiben die Klon-Methode und nie, um es außer vielleicht, um kopieren Arrays. Wenn Sie eine Klasse für die Vererbung entwerfen, beachten Sie, dass Sie keine geschützte Klonmethode bereitstellen möchten. Daher ist für Unterklassen nicht möglich, Cloneable zu implementieren.

Dieses Buch beschreibt auch die vielen Vorteile, die Kopierkonstrukteure über Cloneable/Clone haben.

  • Sie stützen sich nicht auf risikobehaftete außerObjektErstellung Mechanismus
  • Sie verlange nicht nicht durchsetzbar Einhaltung dünn dokumentiert Konventionen
  • Sie mit den richtigen Gebrauch der endgültigen Felder nicht
  • in Konflikt geraten
  • Sie werfen keine unnötigen geprüften Ausnahmen
  • Sie benötigen keine Umwandlungen.

Alle Standardsammlungen verfügen über Kopierkonstruktoren. Benutze sie.

List<Double> original = // some list 
List<Double> copy = new ArrayList<Double>(original); 
+3

Sie kopieren 'original' als 'ArrayList', wenn es sich um einen anderen Listentyp gehandelt haben könnte (z. B.' LinkedList'). Aus diesem Grund ist Klon besser als ein Kopierkonstruktor. –

2

Große Traurigkeit: weder klonbar/Klon noch ein Konstruktor sind große Lösungen: ICH WILL NICHT die implementierende Klasse WISSEN !!! (z. B. - Ich habe eine Map, die kopiert werden soll, mit der gleichen versteckten MumbleMap-Implementierung) Ich möchte nur eine Kopie erstellen, wenn dies unterstützt wird. Aber leider hat Cloneable nicht die clone-Methode, also gibt es nichts, auf das Sie clone() sicher tippen können.

Was auch immer die beste "Kopierobjekt" -Bibliothek da draußen ist, Oracle sollte sie zu einer Standardkomponente der nächsten Java-Version machen (es sei denn, sie ist bereits irgendwo versteckt).

Natürlich, wenn mehr der Bibliothek (z. B. - Sammlungen) unveränderlich wäre, würde diese "Kopie" Aufgabe einfach weggehen. Aber dann würden wir anfangen, Java-Programme mit Dingen wie "Klasseninvarianten" anstatt dem verdammten "Bohnen" -Muster zu entwerfen (ein zerbrochenes Objekt machen und mutieren, bis es gut genug ist).

+0

Es gibt * einige * Hoffnung für diese Art von Sache, zumindest für Wertobjekte, die Sie in Ihrem Projekt machen: https://projectlombok.org/features/experimental/Wither.html – Roboprog

+0

Wenn das Kopieren einfach wäre, hätte es das schon war Teil von Java. Aber es ist nicht. Möchten Sie eine flache Kopie, eine tiefe Kopie oder irgendwo dazwischen? Haben Sie unterschiedliche Verhaltensweisen für verschiedene Klassen, abhängig davon, was Sie kopieren und woran Sie arbeiten? Was passiert mit Generika? Was passiert, wenn das, was du kopierst, ein Parameter für ein Generic ist? Dies könnte ein wenig einfacher zu verstehen sein, ohne Vererbung und ohne Veränderbarkeit, aber diese sind in das Herz von Java (die Sprache) eingebacken. Vielleicht erleichtert eine Sprache wie Scala, die Garantien über die Veränderbarkeit gibt, die Klonbarkeit. – IceArdor