Vorwort
Java Cloning (Klon) ist eines der Merkmale der Java -Sprache, aber es ist selten, es in der Praxis zu verwenden. Aber manchmal ist das Klonen bequemer und effizienter.
Für Klone hat Java einige Einschränkungen:
1. Die klonierte Klasse muss die klonbare Schnittstelle selbst implementieren, um anzuzeigen, dass Object.clone() die Instanz dieser Klasse nach Feld legal kopieren kann. Die klonbare Schnittstelle ist tatsächlich eine Identifikationsschnittstelle und hat keine Schnittstellenmethode.
2. Klassen, die eine klonbare Schnittstelle implementieren, sollten Object.clone überschreiben. Es ist unmöglich, dass ein Objekt nach der Implementierung dieser Schnittstelle es klonen kann. Selbst wenn die Klonmethode reflektierend bezeichnet wird, gibt es keine Garantie dafür, dass sie erfolgreich sein wird.
3. Die Klonierungsmethode in Java.lang.Object ist wie folgt definiert:
geschützter Objekt Clone () wirft ClonenotsuptedEdException aus
Erstellt und gibt eine Kopie dieses Objekts zurück. Es zeigt an, dass es sich um eine geschützte Methode handelt, die im selben Paket sichtbar ist.
Nach Übereinkommen sollte das zurückgegebene Objekt durch Calling super.clone erhalten werden.
Aufgabe in Java
In Java wird die Zuordnung sehr häufig verwendet. Eine einfache Zuordnung ist wie folgt
// Der ursprüngliche Typtyp int a = 1; int b = a; // Referenztyp String [] wochentags = new String [5]; String [] gongzuori = wochentags; // Nur Referenzen kopieren
Im obigen Code.
1. Wenn es sich um den ursprünglichen Datentyp handelt, ist der von der Zuordnung übergebene Wert der reale Wert.
2. Wenn es sich um einen Referenzdatentyp handelt, übergibt die Zuordnung den Verweis auf das Objekt, nicht auf das Objekt.
Das Verständnis des Unterschieds zwischen Datentypen und Referenztypen erleichtert es uns, Klon zu verstehen.
Klon
In Java ist Clon der Prozess des Kopierens eines vorhandenen Objekts in ein anderes Objekt, das dem gleich ist. Das Klonen in Java ist eine Domain-by-Domain-Kopie.
Wenn Sie Klonmethoden in Java unterstützen möchten, müssen Sie zuerst die klonbare Schnittstelle implementieren
Klonbar ist eigentlich ein bisschen seltsam. Es unterscheidet sich von der Schnittstelle, die wir oft verwenden. Es enthält keine Methoden im Inneren, sondern nur eine Markierungsschnittstelle.
Der Quellcode ist wie folgt
öffentliche Schnittstelle klonbar {}Über klonbar, was sollte beachtet werden
1. Wenn Sie Klon unterstützen möchten, müssen Sie die klonbare Schnittstelle implementieren
2. Wenn die Klonmethode nicht zur klonbaren Schnittstelle aufgerufen wird, wird eine Clonenotsupportedexception geworfen.
Schreiben Sie dann die Klonmethode neu und ändern Sie sie auf öffentliche Zugriffsebene
statische Klassenklonable -Implements implementiert klonbares {public int count; öffentliches Kind Kind; @Override public Object Clone () löst ClonenotsupportedException {return Super.clone () aus; }}Rufen Sie die Klonmethode auf, um das Objekt zu kopieren
ClonableImp imp1 = new Clonableicimp (); Imp1.Child = New Child ("Andy"); try {Object obj = imp1.clone (); Klonable IMP2 = (klonable) obj; System.out.println ("Main Imp2.Child.Name =" + imp2.Child.name);} catch (clonenotsupportedexception e) {e.printstacktrace ();}Leichte Kopie
Der im obige Code implementierte Klon ist tatsächlich eine flache Kopie.
Was Sie über eine flache Kopie wissen sollten
1. Verwenden Sie die Standard -Klonmethode
2. Erstellen Sie eine Wertkopie des Originaldatenfelds
3. kopieren nur Referenzen als Referenztypen
4. Schnelle Ausführung und hohe Effizienz
5. Die Daten können nicht um 100%getrennt werden.
6. Wenn ein Objekt nur die ursprüngliche Datendomäne oder die unveränderliche Objektdomäne enthält, wird empfohlen, eine flache Kopie zu verwenden.
In Bezug auf die Unfähigkeit, Daten zu trennen, können wir diesen Code verwenden, um ihn zu überprüfen.
ClonableImp imp1 = new Clonableicimp (); Imp1.Child = New Child ("Andy"); try {Object obj = imp1.clone (); Klonable IMP2 = (klonable) obj; Imp2.Child.Name = "Bob"; System.out.println ("Haupt imp1.child.name =" + imp1.child.name);} catch (clonenotsuptedException e) {e.printstacktrace ();} Im obigen Code verwendeten wir die Klonmethode von Imp1, um Imp2 zu klon, dann imp2.child.name an Bob und druckte dann imp1.child.name , um das Ergebnis zu erzielen.
Hauptimp1.Child.Name = Bob
Der Grund dafür ist, dass die flache Kopie keine 100% ige Trennung der Daten erreicht. Imp1 und Imp2 teilen das gleiche Kinderobjekt, sodass eine Änderung die andere beeinflusst.
Tiefe Kopie
Eine tiefe Kopie kann das Problem der 100% igen Datentrennung lösen. Nehmen Sie einfach einige Änderungen am obigen Code vor.
1. Kind implementiert die klonbare Schnittstelle.
Public Class Child Implements Clonable {Public String Name; öffentliches Kind (Zeichenfolge Name) {this.name = name; } @Override public String toString () {return "child [name =" + name + "]"; } @Override protected Object Clone () löscht ClonenotsuptedEdException {return Super.clone (); }}2. Schreiben Sie die Klonmethode neu und rufen Sie die Klonmethode der Datendomäne auf.
statische Klassenklonable -Implements implementiert klonbares {public int count; öffentliches Kind Kind; @Override public Object Clone () löst Clonenotsupportedexception {Clonableable Obj = (Clonableable) Super.clone (); Obj.Child = (Kind) Kind.Clone (); Rückkehr obj; }} Wenn wir imp2.child.name erneut ändern, wirkt sich der Wert von imp1.child.name nicht aus, da Imp1 und Imp2 jeweils ihre eigenen Kinderobjekte haben, da die Daten zu 100% isoliert sind.
Einige Merkmale von Deep Copy
1. Sie müssen die Klonmethode überschreiben und nicht nur die übergeordnete Klassenmethode aufrufen, sondern auch die Klonmethode des Attributs aufrufen.
2. 100% Datentrennung zwischen dem ursprünglichen Objekt und dem klonierten Objekt wird erreicht
3. Wenn das Objekt über ein Referenztyp -Attribut verfügt, wird empfohlen, Deep Copy zu verwenden.
V.
Warum Klonen verwenden?
Es ist sehr wichtig und häufig: Eine API muss eine Listensammlung bereitstellen, aber sie möchte nicht, dass die Änderung des Anrufers ihre eigenen Änderungen beeinflusst. Daher muss sie ein Objekt klonen, um den Zweck der Datenisolierung zu erreichen.
Cloone sollte so weit wie möglich vermieden werden
1. Normalerweise wird die Schnittstelle implementiert, um zu zeigen, was die Klasse für ihre Kunden tun kann, während klonbar nur eine Tag-Schnittstelle ist, und es ändert auch das Verhalten der handgeschützten Methode in der Superklasse. Es ist eine äußerst atypische Verwendung der Schnittstelle und ist der Nachahmung nicht wert.
2. Die Javadoc
Die Klonmethode erstellt und gibt eine Kopie des Objekts zurück. Die genaue Bedeutung der Kopie hängt von der Klasse des Objekts ab. Die allgemeine Bedeutung ist, dass für jedes Objekt X der Ausdruck
x.clone() != x 为true x.clone().getClass() == x.getClass() gibt ebenfalls true zurück, aber nicht erforderlich x.clone().equals(x) gibt ebenfalls wahr, aber nicht notwendig, aber nicht notwendig
Der zweite und dritte Ausdruck oben geben leicht false zurück. Daher ist das einzige, was permanent true garantieren kann, der Ausdruck eins, dh die beiden Objekte sind unabhängige Objekte.
3. Die endgültige Domäne des variablen Objekts. Wenn wir bei der Klonierungsmethode die endgültige Domäne des Variablenobjekts kopieren müssen, ist es aufgrund der endgültigen Beschränkungen tatsächlich unmöglich, zu kompilieren und zu bestehen. Um das Klonieren zu implementieren, müssen wir daher in Betracht ziehen, das endgültige Schlüsselwort der mütterlichen Objektdomäne aufzugeben.
4. Thread-Sicherheit Wenn Sie sich für Thread-Safe-Klassen zur Implementierung der klonbaren Schnittstelle entscheiden, müssen Sie sicherstellen, dass die Klonmethode synchronisiert ist. Das Standard Object.clone -Methode wird nicht synchronisiert.
Im Allgemeinen ist die Klonmethode in Java nicht wirklich perfekt, daher wird empfohlen, sie so weit wie möglich zu vermeiden. Hier sind einige Alternativen.
Konstruktoren kopieren
Kopieren von Objekten können auch mit einem Kopierkonstruktor implementiert werden.
1. Kopieren von Konstruktor ist auch eine Art Konstruktor
2. Es wird nur ein Parameter akzeptiert, der Parametertyp ist die aktuelle Klasse
3.. Der Zweck ist es, ein neues Objekt mit den gleichen Parametern wie zu generieren wie
4. Der Vorteil des Kopierkonstruktors gegenüber der Klonmethode besteht darin, dass sie einfach und einfach zu implementieren ist.
Ein Beispielcode unter Verwendung eines Kopierkonstruktors
public Class Car {Wheel Wheel; Streicherhersteller; öffentliches Auto (Radrad, Streicherhersteller) {this.wheel = Wheel; this.manufacturer = Hersteller; } // Constructor Public Car (Car Car) {this (Car.Wheel, Car.Manufacturer); } public static Class Wheel {String Marke; }}Beachten Sie, dass der obige Code als flaches Kopie implementiert wird. Wenn Sie eine tiefe Kopie implementieren möchten, lesen Sie bitte den folgenden Code.
// Copy ConstructorPublic Car (Car Car) {Wheel Wheel = New Wheel (); Wheel.Brand = Car.Wheel.Brand; this.wheel = wheel; this.manufacturer = car.manufacturer;}Für mehr Bequemlichkeit können wir der obigen Klasse auch eine statische Methode hinzufügen
öffentliches statisches Auto Newinstance (Car Car) {Neues Auto zurückgeben (Auto);}Verwenden Sie serialisierbar, um eine tiefe Kopie zu erreichen
Tatsächlich kann eine tiefe Kopie von Objekten mithilfe der Serialisierung erreicht werden. Der kurze Code lautet wie folgt
öffentliche Klasse DeepCopyExample implementiert serialisierbar {private statische endgültige lange Serialversionuid = 6098694917984051357L; öffentliches Kind Kind; public DeepCopyExample Copy () {DeepCopyExample Copie = null; Versuchen Sie {bytearrayoutputStream baos = new bytearrayoutputStream (); ObjectOutputStream OOS = new ObjectOutputStream (BAOS); oos.writeObject (this); BytearrayInputStream bais = new bytearrayInputStream (baos.tobytearray ()); ObjectInputStream OIS = New ObjectInputStream (BAIS); Copy = (DeepCopyExample) ois.ReadObject (); } catch (ioException e) {e.printstacktrace (); } catch (classNotFoundException e) {e.printstacktrace (); } Rückgabekopie; }}Unter ihnen muss das Kind die serialisierbare Schnittstelle implementieren
Public Class Child implementiert serialisierbar {private statische endgültige lange Serialversionuid = 6832122780722711261L; public String name = ""; öffentliches Kind (Zeichenfolge Name) {this.name = name; } @Override public String toString () {return "child [name =" + name + "]"; }}Verwenden Sie Beispiele und Testcode
DeepCopyExample Beispiel = new DeepCopyExample (); Beispiel.Child = New Child ("Beispiel"); DeepCopyExample Copy = Beispiel.Copy (); if (copy! = null) {copy.child.name = "kopiert"; System.out.println ("example.child =" + example.child + "; copy.child =" + copy.child);} // Ausgabeergebnis: Beispiel.Child = child [name = Beispiel]; copy.child = child [name = kopiert]Nach den Ausgabeergebnissen zu beurteilen, wirkt sich die Änderung des untergeordneten Werts des Kopierobjekts nicht auf den untergeordneten Wert des Beispielobjekts aus, dh die Serialisierung, um eine tiefe Kopie des Objekts zu erreichen.
Zusammenfassen
Das obige ist der gesamte Inhalt des Klonen in Java. Ich hoffe, dieser Artikel wird für alle hilfreich sein, Java zu lernen.