Bevor wir das Thema offiziell eintreten, verstehen wir zunächst die Konzepte der tiefen Kopie und der Vorkopie:
Leichte Kopie:
Es wird ein neues Objekt erstellt, das eine genaue Kopie des Eigenschaftswert des ursprünglichen Objekts enthält. Wenn das Attribut ein Basistyp ist, wird der Wert des Grundtyps kopiert. Wenn es sich bei dem Attribut um eine Speicheradresse handelt, wird die Speicheradresse kopiert. Wenn ein Objekt diese Adresse ändert, wirkt sich dies auf ein anderes Objekt aus.
Tiefe Kopie:
Sie möchten nicht nur alle nicht referenzierten Elementvariablenwerte des Objekts kopieren, sondern Sie müssen auch eine neue Instanz für Mitgliedsvariablen des Referenztyps erstellen und in den formalen Parameterinstanzwert initialisieren.
Lassen Sie uns nach dem Verständnis des Konzepts testen, ob gewöhnliche Objektzuweisungsvorgänge eine tiefe Kopie oder eine flache Kopie sind:
Testcode:
public classtiefekopie {public static void main (String [] args) {Copy first = new Copy ("Hzw", 24); Kopieren Sie Sekunde = zuerst; Second.name = "Shanxi"; System.out.println (first.name); // Ausgabe shanxi}} coxy {public String name; öffentliches int Alter; public Copy (String -Name, int age) {this.name = name; this.age = Alter; }} Es ist festzustellen, dass nach dem zweiten Änderungsmodifizieren des NAME -Attributwerts an Shanxi auch der Attributwert des Vornamens zu Shanxi wird. Dies zeigt, dass gewöhnliche Objektzuweisungen zu flachen Kopien gehören;
Nach dem Verständnis, ob es sich bei der Zuordnung zwischen Objekten um eine flache Kopie handelt, sehen wir, ob das Klonen eine tiefe Kopie oder eine flache Kopie ist. Der Testcode soll das obige Kopierobjekt aktivieren, um die Klonmethode in der klonbaren Schnittstelle zu implementieren:
public classtiefekopie {public static void main (String [] args) {Copy first = new Copy ("Hzw", 24); Kopieren Sie Second = null; try {Second = (Copy) first.clone (); } catch (clonenotsUsPortedexception e) {e.printstacktrace (); } Second.Name = "Shanxi"; System.out.println(first.name);//Output: hzw System.out.println(first);//Output: com.hzw.day33.Copy@7f39ebdb System.out.println(second);//Output: com.hzw.day33.Copy@33abb81e } } class Copy implements Cloneable { public String name; öffentliches int Alter; public Copy (String -Name, int age) {this.name = name; this.age = Alter; } @Override protected Object Clone () löscht ClonenotsuptedEdException {return Super.clone (); }}Es ist ersichtlich, dass das ursprünglich erstellte Objekt zuerst und das geklonte Objekt zweitens zwei Instanzen sind, sodass die Änderung des Namensattributs im zweiten Mal das Namensattribut in erster Stelle nicht beeinflusst. Wir können jedoch nicht einfach glauben, dass das Klonen eine tiefe Kopie wie das folgende Beispiel ist:
public classtiefenkopie {public static void main (String [] args) {Student Student = New Student (95); Kopieren Sie First = New Copy ("Hzw", 24, Student); Kopieren Sie Second = null; try {Second = (Copy) first.clone (); } catch (clonenotsUsPortedexception e) {e.printstacktrace (); } Second.Name = "Shanxi"; Second.Student.Score = 60; System.out.println (first == zweiten); // false System.out.println (first.student == zweiten.student); // true system.out.println (first.student.score); // 60}} Klassenkopie implementiert klonbar {public String name; öffentliches int Alter; öffentlicher Student; public Copy (Zeichenfolge Name, int Alter, Student Student) {this.name = name; this.age = Alter; this.student = Student; } @Override protected Object Clone () löscht ClonenotsuptedEdException {return Super.clone (); }} Klasse Schüler {public int Score; public student (int Score) {this.score = Score; }}Hast du es gesehen? Wir haben den zweiten durch Klonen erstellt, und es ist offensichtlich, dass erste und zweite zwei Instanzen sind, da die Ausgabe von First == zweitens falsch ist, aber die Schülerobjekte im ersten und zweiten sind gleich. Nachdem sich der Bewertungswert des Schülers bis zum zweiten Mal geändert hatte, änderte sich auch die Punktzahl des Schülers zuerst. Dies bedeutet, dass der Student in erster und zweiter Stelle gleich ist. Dies bedeutet, dass das Klonen eine flache Kopie ist. Wenn wir eine tiefe Kopie des Klonen implementieren möchten, müssen wir das Schülerobjekt im Kopierobjekt auch die Klonmethode in der klonbaren Schnittstelle implementieren lassen, und die Klonmethode in Kopie gibt einen Schülerklon zurück, damit der Schüler eindeutig sein kann. Der geänderte Code lautet wie folgt:
public classtiefenkopie {public static void main (String [] args) {Student Student = New Student (95); Kopieren Sie First = New Copy ("Hzw", 24, Student); Kopieren Sie Second = null; try {Second = (Copy) first.clone (); } catch (clonenotsUsPortedexception e) {e.printstacktrace (); } Second.Name = "Shanxi"; Second.Student.Score = 60; System.out.println (first == zweiten); // false System.out.println (first.student == zweiten.student); // false system.out.println (first.Student.score); // 95 System.out.println (zweite.student.score); // 60}}}}}}}}}}}}}}} copy copy copyablement klonable {public); öffentliches int Alter; öffentlicher Student; public Copy (Zeichenfolge Name, int Alter, Student Student) {this.name = name; this.age = Alter; this.student = Student; } @Override protected Object Clone () löscht ClonenotsuptedEdException {Copy = (Copy) Super.clone (); copy.student = (student) student.clone (); Rückgabekopie; }} Klasse Schüler implementiert klonbar {public int Score; public student (int Score) {this.score = Score; } @Override protected Object Clone () löscht ClonenotsuptedEdException {return Super.clone (); }} Sie können das zuerst und zweite, zuerst sehen. Nachdem wir die Punktzahl des zweiten Schülers geändert haben, hat es daher keinen Einfluss auf den Punktzahl des Schülers im ersten und erreicht den Zweck des tiefen Kopierens.
Wenn Sie jedoch sorgfältig darüber nachdenken, wird das Problem auftreten. Wenn in unserem obigen Beispiel auch Referenztypen in der Schülerklasse vorhanden sind, z. B. in der College -Klasse, müssen wir die College -Klasse die klonbare Schnittstelle implementieren lassen und dann die Klone -Methode der College -Klasse in der Klonmethode in der Schülerklasse aufrufen und die Klassenmethode der Schülerklasse in der Klonmethode der Kopieklasse aufrufen. Ich fand, dass es weg war. Dieser Prozess ist so kompliziert. Alle relevanten Referenztypen in der Klasse müssen die klonbare Schnittstelle implementieren. Ich fühle, dass es so mühsam ist, okay, das nächste ist großartig zu sein.
Der beste Weg, um das Problem der Tiefenkopie zu lösen, besteht darin, die Serialisierung zu verwenden, damit nicht alle Klassen die klonbare Schnittstelle implementieren müssen, sondern nur direkt serialisieren und deserialisieren müssen. Schauen wir uns an.
Import Java.io.file; import Java.io.FileInputStream; importieren java.io.fileoutputStream; importieren java.io.objectinputStream; importieren java.io.objectoutputStream; importieren java.io.serializable; public classtiefenkopie {public static void main (String [] args) {College School = New College ("nongda"); Schülerstudent = neuer Schüler (95, Schule); Copy copy = new Copy ("Hzw", 23, Student); Kopieren Sie ein anderes = null; // Geben Sie die Deserialized -Klasse -Instanz an // Serialisieren Sie den Serialisierungsvorgang Try {FileOutputStream fos = new FileOutputStream (neue Datei ("d: /copy.txt"); ObjectOutputStream OOS = New ObjectOutputStream (FOS); OOS.WriteObject (Kopie); } catch (Ausnahme e) {e.printstacktrace (); } // serialisieren die Deserialisierungsoperation FileInputStream FIS; try {fis = new FileInputStream (neue Datei ("d: /copy.txt")); ObjectInputStream OIS = New ObjectInputStream (FIS); ein anderes = (kopieren) ois.readObject (); } catch (Ausnahme e) {e.printstacktrace (); } System.out.println (copy == ein anderer); // false System.out.println (Copy.student == Another.student); // false System.out.println (Copy.Student.School == Another.Student.Shool); // false.student.School.Shoolname = "Wuda";; System.out.println (Copy.Student.School.SchoolName); // nongda}} Klasse Kopie implementiert serialisierbar {public String name; öffentliches int Alter; öffentlicher Student; public Copy (Zeichenfolge Name, int Alter, Student Student) {this.name = name; this.age = Alter; this.student = Student; }} Klasse Schüler implementiert serialisierbar {public int Score; öffentliche College -Schule; öffentlicher Schüler (int Score, College School) {this.score = Score; this.school = Schule; }} Klasse College implementiert serialisierbare {public String schulname; public College (String SchoolName) {this.Schoolname = schulname; }} Aus der Ausgabe können wir sehen, dass das nach der Deserialisierung generierte Objekt eine Kopie des ursprünglichen Objekts ist und keine Beziehung zum ursprünglichen Objekt mit Ausnahme desselben Attributwerts hat. Wenn wir den Schulnamen der von der Deserialisierung erzeugten Objekt an "Wuda" ändern, haben wir den Schulnamen der ursprünglichen Instanz nicht geändert und wir haben immer noch "nongda" ausgegeben, sodass wir den wirklichen tiefen Kopiereffekt erreicht haben. Um eine Serialisierung zu erreichen, müssen alle relevanten Klassen die serialisierbare Schnittstelle implementieren, die immer bequemer ist als die Implementierung sowohl der klonbaren Schnittstelle als auch der Klonmethode.
Das obige ist eine detaillierte Erklärung von Java Deep und Shallow Exemplare. Wenn Sie es benötigen, beziehen Sie sich bitte darauf.