Ich frage mich, ob es eine empfohlene Methode gibt, um Deep Instance in Java zu klonen / zu kopieren.
Ich habe 3 Lösungen im Sinn, aber ich kann einige verpassen, und ich würde gerne Ihre Meinung haben
Bearbeiten: Bohzo-Vorschlag einschließen und Frage verfeinern: Es geht mehr um tiefes Klonen als um flaches Klonen.
Mach es selbst:
Codieren Sie die Eigenschaften des Klons von Hand nach den Eigenschaften und überprüfen Sie, ob auch veränderbare Instanzen geklont werden.
pro:
- Kontrolle darüber, was ausgeführt wird
- schnelle Ausführung
Nachteile:
- mühsam zu schreiben und zu warten
- fehleranfällig (Fehler beim Kopieren / Einfügen, fehlende Eigenschaft, neu zugewiesene veränderbare Eigenschaft)
Verwenden Sie Reflexion:
Mit Ihren eigenen Reflexionswerkzeugen oder mit einem externen Helfer (wie Jakarta Common-Beans) ist es einfach, eine generische Kopiermethode zu schreiben, die die Arbeit in einer Zeile erledigt.
Pro:
- Einfach zu schreiben
- Keine Wartungsprobleme
:
- Weniger Kontrolle darüber, was passiert
- Fehler bei veränderlichen Objekten, wenn das Reflection-Tool nicht auch Unterobjekte klont
- Langsamere Ausführung
Verwenden Sie das Klon-Framework:
Verwenden Sie ein Framework, das dies für Sie erledigt, z. B .:
Commons-lang SerializationUtils
Java Deep Cloning Library
Dozer
Kryo
pro:
- genau wie Reflexion
- mehr Kontrolle darüber, was genau geklont werden soll.
Nachteile:
- Jede veränderbare Instanz wird auch am Ende der Hierarchie vollständig geklont. Die
Ausführung kann sehr langsam sein
Verwenden Sie die Bytecode-Instrumentierung, um zur Laufzeit einen Klon zu schreiben
javassit , BCEL oder cglib können verwendet werden, um einen dedizierten Kloner so schnell wie eine geschriebene Hand zu generieren. Kennt jemand eine Bibliothek, die eines dieser Tools für diesen Zweck verwendet?
Was habe ich hier vermisst?
Welches würdest du empfehlen?
Vielen Dank.
Antworten:
Für tiefes Klonen (klont die gesamte Objekthierarchie):
commons-lang SerializationUtils - mithilfe der Serialisierung - wenn alle Klassen unter Ihrer Kontrolle stehen und Sie die Implementierung erzwingen können
Serializable
.Java Deep Cloning Library - mithilfe von Reflection - in Fällen, in denen die Klassen oder Objekte, die Sie klonen möchten, außerhalb Ihrer Kontrolle liegen (eine Bibliothek eines Drittanbieters) und Sie sie nicht implementieren
Serializable
können oder in Fällen, die Sie nicht implementieren möchtenSerializable
.Für flaches Klonen (klont nur die Eigenschaften der ersten Ebene):
commons-beanutils BeanUtils - in den meisten Fällen.
Spring BeanUtils - Wenn Sie Spring bereits verwenden und dieses Dienstprogramm daher im Klassenpfad haben.
Ich habe bewusst auf die Option "Do-it-yourself" verzichtet. Die oben genannten APIs bieten eine gute Kontrolle darüber, was geklont werden soll und was nicht (z. B. mit
transient
oderString[] ignoreProperties
), sodass eine Neuerfindung des Rads nicht bevorzugt wird.quelle
Joshua Blochs Buch enthält ein ganzes Kapitel mit dem Titel "Punkt 10: Klon mit Bedacht überschreiben", in dem er erklärt, warum das Überschreiben von Klonen größtenteils eine schlechte Idee ist, da die Java-Spezifikation dafür viele Probleme verursacht.
Er bietet einige Alternativen:
Verwenden Sie anstelle eines Konstruktors ein Factory-Muster:
Verwenden Sie einen Kopierkonstruktor:
Alle Auflistungsklassen in Java unterstützen den Kopierkonstruktor (z. B. new ArrayList (l);)
quelle
Copyable
Schnittstelle definiert , die einegetCopy()
Methode enthält . Verwenden Sie das Prototypmuster einfach manuell.newInstance()
Methode und derYum
Konstruktor würden tiefe oder flache Kopien machen?Seit Version 2.07 unterstützt Kryo das flache / tiefe Klonen :
Kryo ist schnell, auf und von ihrer Seite finden Sie möglicherweise eine Liste der Unternehmen, die es in der Produktion verwenden.
quelle
Verwenden Sie XStream toXML / fromXML im Speicher. Extrem schnell und gibt es schon lange und es geht stark. Objekte müssen nicht serialisierbar sein und Sie müssen keine Reflektion verwenden (obwohl XStream dies tut). XStream kann Variablen erkennen, die auf dasselbe Objekt verweisen, und nicht versehentlich zwei vollständige Kopien der Instanz erstellen. Viele solche Details wurden im Laufe der Jahre herausgearbeitet. Ich habe es für eine Reihe von Jahren verwendet und es ist ein go to. Es ist ungefähr so einfach zu bedienen, wie Sie sich vorstellen können.
oder
Klonen,
Genauer gesagt:
quelle
Für komplizierte Objekte und wenn die Leistung nicht signifikant ist, verwende ich gson, um das Objekt in json-Text zu serialisieren, und deserialisiere dann den Text, um ein neues Objekt zu erhalten.
gson, das auf Reflexion basiert, funktioniert in den meisten Fällen, außer dass
transient
Felder nicht kopiert werden und Objekte mit Zirkelverweis mit UrsacheStackOverflowError
.quelle
Hängt davon ab.
Verwenden Sie für Geschwindigkeit DIY. Verwenden Sie zum Schutz vor Kugeln die Reflexion.
Übrigens ist die Serialisierung nicht dasselbe wie refl, da einige Objekte möglicherweise überschriebene Serialisierungsmethoden (readObject / writeObject) bereitstellen und fehlerhaft sein können
quelle
Ich würde den DIY-Weg empfehlen, der in Kombination mit einer guten hashCode () - und equals () -Methode in einem Unit-Test leicht zu beweisen sein sollte.
quelle
Ich würde vorschlagen, Object.clone () zu überschreiben, zuerst super.clone () aufzurufen und dann ref = ref.clone () für alle Referenzen aufzurufen, die Sie tief kopieren möchten. Es ist mehr oder weniger Do-it-yourself- Ansatz, benötigt aber etwas weniger Codierung.
quelle
Implementieren Sie für das Deep Cloning Serializable für jede Klasse, die Sie so klonen möchten
Und dann nutzen Sie diese Funktion:
so was:
Obj newObject = (Obj)deepClone(oldObject);
quelle