Gibt es ein Dienstprogramm zum tiefen Klonen für Java-Sammlungen:
- Arrays
- Listen
- Karten
HINWEIS: Bevorzugen Sie eine Lösung ohne Verwendung der Serialisierung, jedoch unter Verwendung der Object.clone () -Methode. Ich kann sicher sein, dass mein benutzerdefiniertes Objekt die Methode clone () implementiert und nur Java-Standardklassen verwendet, die klonbar sind ...
Antworten:
Ich denke, die vorherige grüne Antwort war schlecht , warum könnten Sie fragen?
Oh, und übrigens ist die Serialisierung auch schlecht. Möglicherweise müssen Sie überall Serializable hinzufügen (das bringt mich auch zum Weinen).
Was ist die Lösung:
Java Deep-Cloning-Bibliothek Die Cloning-Bibliothek ist eine kleine Open-Source-Java-Bibliothek (Apache-Lizenz), die Objekte tief klont. Die Objekte müssen die klonbare Schnittstelle nicht implementieren. Tatsächlich kann diese Bibliothek JEDE Java-Objekte klonen. Es kann verwendet werden, dh in Cache-Implementierungen, wenn Sie nicht möchten, dass das zwischengespeicherte Objekt geändert wird, oder wenn Sie eine tiefe Kopie von Objekten erstellen möchten.
Cloner cloner=new Cloner(); XX clone = cloner.deepClone(someObjectOfTypeXX);
Überprüfen Sie es unter https://github.com/kostaskougios/cloning
quelle
Alle Ansätze zum Kopieren von Objekten in Java weisen schwerwiegende Mängel auf:
Klon
class
Feld zuweisen (über das Sie lesen könnengetClass()
) und die Felder des Originals kopieren.Weitere Probleme mit clone () finden Sie in Punkt 11 von Joshua Blochs Buch " Effective Java, Second Edition ".
Serialisieren
Serialisieren ist noch schlimmer; es hat viele der Mängel von
clone()
und noch einige mehr. Joshua hat ein ganzes Kapitel mit vier Punkten allein für dieses Thema.Meine Lösung
Meine Lösung besteht darin, meinen Projekten eine neue Oberfläche hinzuzufügen:
public interface Copyable<T> { T copy (); T createForCopy (); void copyTo (T dest); }
Der Code sieht folgendermaßen aus:
class Demo implements Copyable<Demo> { public Demo copy () { Demo copy = createForCopy (); copyTo (copy); return copy; } public Demo createForCopy () { return new Demo (); } public void copyTo (Demo dest) super.copyTo (dest); ...copy fields of Demo here... } }
Leider muss ich diesen Code in alle meine Objekte kopieren, aber es ist immer der gleiche Code, sodass ich eine Eclipse-Editor-Vorlage verwenden kann. Vorteile:
Für Standard-Java-Typen (wie Sammlungen usw.) verwende ich eine Dienstprogrammklasse, die diese kopieren kann. Die Methoden haben Flags und Callbacks, sodass ich steuern kann, wie tief eine Kopie sein soll.
quelle
Das flache Klonen einer Sammlung ist einfach, aber wenn Sie tief klonen möchten, ist eine Bibliothek wahrscheinlich besser als das manuelle Codieren (da Sie auch die Elemente in der Sammlung klonen möchten ).
Genau wie diese Antwort habe ich die Cloner-Bibliothek verwendet und die Leistung speziell gegen XStream (das durch Serialisieren und Deserialisieren "klonen" kann) und binäre Serialisierung getestet. Obwohl XStream sehr schnell in / aus XML serialisiert, ist Cloner beim Klonen viel schneller:
0,0851 ms: xstream (Klonen durch Serialisieren / Deserialisieren)
0,0223 ms: Binäre Serialisierung (Klonen durch Serialisieren / Deserialisieren)
0,0017 ms: Kloner
* durchschnittliche Zeit zum Klonen eines einfachen Objekts (zwei Felder) und kein öffentlicher Standardkonstruktor. 10.000 Mal ausführen.
Neben der Schnelligkeit gibt es noch weitere Gründe, sich für Cloner zu entscheiden:
Einfach zu verwenden. Beispiel:
cloner.deepClone (anyObject);
quelle
Ich bin der Schöpfer der Cloner Lib, die Brad vorgestellt hat. Dies ist eine Lösung zum Klonen von Objekten, ohne dass zusätzlicher Code geschrieben werden muss (keine serialisierbaren Objekte oder impl clone () -Methode erforderlich).
Es ist ziemlich schnell, wie Brad sagte, und kürzlich habe ich eine Version hochgeladen, die noch schneller ist. Beachten Sie, dass die manuelle Implementierung einer clone () -Methode schneller ist als die von clone lib, aber andererseits müssen Sie viel Code schreiben.
Cloner lib hat für mich sehr gut funktioniert, da ich es in einer Cache-Implementierung für eine Site mit sehr viel Verkehr (~ 1 Million Anfragen / Tag) verwende. Der Cache sollte ungefähr 10 Objekte pro Anforderung klonen. Es ist sehr zuverlässig und stabil. Beachten Sie jedoch, dass das Klonen nicht ohne Risiko ist. Die Bibliothek kann so konfiguriert werden, dass sie jede Klasseninstanz druckt, die sie während der Entwicklung klont. Auf diese Weise können Sie überprüfen, ob es klont, was Ihrer Meinung nach geklont werden sollte. Objektdiagramme können sehr tief sein und Verweise auf eine überraschend große Anzahl von Objekten enthalten. Mit clone lib können Sie anweisen, die nicht gewünschten Objekte, dh Singletons, nicht zu klonen.
quelle
Eine allgemeine Möglichkeit, eine beliebige Sammlung tief zu klonen, besteht darin, sie in einen Stream zu serialisieren und dann in eine neue Sammlung zurückzulesen. Sie werden völlig neue Objekte rehydrieren, die keine Beziehung zu den alten haben, außer identische Kopien zu sein.
In Brunos Antwort finden Sie einen Link zu den Apache Commons-Dienstprogrammklassen für die Serialisierung. Dies ist sehr hilfreich, wenn Sie sich für diesen Weg entscheiden.
quelle
Eine Möglichkeit ist die Verwendung der Serialisierung :
Apache Commons bietet SerializationUtils
quelle
Ich habe diese Klonbibliothek verwendet und fand sie sehr nützlich. Da es einige Einschränkungen gab (ich brauchte eine genauere Kontrolle über den Klonprozess: Welches Feld, in welchem Kontext und wie tief sollte geklont werden usw.), habe ich eine erweiterte Version davon erstellt. Sie steuern das Klonen der Felder, indem Sie sie in der Entitätsklasse mit Anmerkungen versehen.
Um einen Eindruck davon zu bekommen, hier eine Beispielklasse:
public class CloneMePlease { @Clone(Skip.class) String id3 = UUID.randomUUID().toString(); @Clone(Null.class) String id4 = UUID.randomUUID().toString(); @Clone(value = RandomUUID.class, groups=CustomActivationGroup1.class) String id5 = UUID.randomUUID().toString(); @Clone.List({ @Clone(groups=CustomActivationGroup2.class, value=Skip.class), @Clone(groups=CustomActivationGroup3.class, value=Copy.class)}) Object activationGroupOrderTest = new Object(); @Clone(LongIncrement.class) long version = 1l; @PostClone private void postClone(CloneMePlease original, @CloneInject CloneInjectedService service){ //do stuff with the original source object in the context of the cloned object //you can inject whatewer service you want, from spring/guice to perform custom logic here } }
Weitere Details hier: https://github.com/mnorbi/fluidity-cloning
Es gibt auch eine hibernate-spezifische Erweiterung, falls diese benötigt wird.
quelle
Verwenden Sie die Serialisierung und dann die Deserialisierung. Beachten Sie jedoch, dass dieser Ansatz nur mit serialisierbaren Klassen ohne transiente Felder funktioniert. Außerdem werden Ihre Singletons keine Singletons mehr sein.
quelle