La copie profonde (copie profonde) et la copie superficielle (copie superficielle) sont deux concepts relativement courants, notamment dans le langage C++. Si vous ne le comprenez pas, vous aurez des problèmes lors de la suppression, mais heureusement, nous utilisons Java ici. Bien que Java gère automatiquement le recyclage des objets, il faut quand même prêter suffisamment d'attention à la copie profonde (deep copy) et à la copie superficielle (shallow copy), car parfois ces deux concepts nous apportent souvent beaucoup de confusion.
La copie superficielle signifie que lors de la copie d'un objet, seul l'objet lui-même (y compris les variables de base de l'objet) est copié, mais l'objet pointé par la référence contenue dans l'objet n'est pas copié. Une copie complète copie non seulement l'objet lui-même, mais copie également tous les objets pointés par les références contenues dans l'objet. Par exemple, pour que ce soit plus clair : l'objet A1 contient une référence à B1, et B1 contient une référence à C1. Copie superficielle A1 pour obtenir A2 contient toujours une référence à B1 et B1 contient toujours une référence à C1. La copie profonde est la récursion de la copie superficielle A1 pour obtenir A2 contient une référence à B2 (copie de B1) et B2 contient une référence à C2 (copie de C1).
Si la méthode clone() n'est pas réécrite, l'objet obtenu en appelant cette méthode est une copie superficielle. Concentrons-nous sur la copie complète ci-dessous.
Exécutez le programme suivant pour jeter un œil à la copie superficielle :
class Professor0 implémente Cloneable { String name; Professor0(String name, int age) { this.name = name; this.age = age; } public Object clone() throws CloneNotSupportedException { return super.clone(); la classe Student0 implémente Cloneable { Nom de la chaîne ; // Objet constant. int age;Professeur0 p;//Les valeurs de référence de l'étudiant 1 et de l'étudiant 2 sont les mêmes. Student0 (String name, int age, Professor0 p) { this.name = name; this.age = age; this.p = p; } public Object clone() { Student0 = null ; .clone(); } catch (CloneNotSupportedException e) { System.out.println(e.toString()); return o; } } public class ShallowCopy { public static void main(String[] args) { Professeur0 p = nouveau Professeur0("wangwu", 50); Étudiant0 s1 = nouveau Étudiant0("zhangsan", 18, p); Étudiant0 s2 = (Étudiant0) s1.clone(); p.name = "lisi"; s2.p.age = 30; s2.name = "z"; System.out.println("Nom de l'étudiant s1 :" + s1.name + "/n Nom du professeur de l'étudiant s1 :" + s1.p.name + "," + "/n Âge du professeur de l'étudiant s1" + s1 .p.age);//Professeur de l'élève 1} }
s2 a changé, mais s1 a également changé, prouvant que p de s1 et p de s2 pointent vers le même objet. Ce n'est pas le cas dans nos besoins réels, nous avons donc besoin d'une copie complète :
class Professor implémente Cloneable { String name; Professeur (String name, int age) { this.name = name; this.age = age; } public Object clone() { Object o = null; clone(); } catch (CloneNotSupportedException e) { System.out.println(e.toString() ); return o; } } class Student implémente Cloneable { String name ; int age; Professeur p; Étudiant (Nom de la chaîne, int âge, Professeur p) { this.name = name; this.age = age; this.p = p; o = (Étudiant) super.clone(); } catch (CloneNotSupportedException e) { System.out.println(e.toString() } op = (Professeur) p.clone(); return o; } } public class DeepCopy { public static void main(String args[]) { long t1 = System.currentTimeMillis(); = nouvel étudiant("zhangsan", 18, p); Étudiant s2 = (Étudiant) s1.clone(); s2.p.name = "lisi"; s2.p.age = 30; System.out.println("name=" + s1.p.name + "," + "age=" + s1.p.age); // Le professeur de l'étudiant 1 ne change pas. long t2 = System.currentTimeMillis(); System.out.println(t2-t1 } }
Bien entendu, nous disposons également d’une méthode de copie profonde, qui consiste à sérialiser l’objet :
import java.io.*; //La sérialisation prend du temps, la classe Professor2 implémente Seriallessly { /** * */ private static final serialVersionUID = 1L; String name; Professor2 (String name, int age) { this. name = name; this.age = age; } } class Student2 implémente Serialisable { /** * */ private static final serialVersionUID = 1L ; objet constant. int age;Professeur2 p;//Les valeurs de référence de l'étudiant 1 et de l'étudiant 2 sont les mêmes. Student2 (String name, int age, Professor2 p) { this.name = name; this.age = age; this.p = p; } public Object deepClone() throws IOException,OptionalDataException, ClassNotFoundException { // Écrivez l'objet dans le flux In ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream oo = new ObjectOutputStream(bo); oo.writeObject(this); // Lire ByteArrayInputStream à partir du flux bi = new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream oi = new ObjectInputStream(bi); return (oi.readObject()); /** * @param args */ public static void main(String[] args) lance une exception OptionDataException, IOException, ClassNotFoundException { long t1 = System.currentTimeMillis(); Professeur2 p = nouveau Professeur2("wangwu", 50); Étudiant2 s1 = nouveau Étudiant2("zhangsan", 18, p); (); s2.p.name = "lisi"; s2.p.age = 30; System.out.println("name=" + s1.p.name + "," + "age=" + s1.p.age); // Le professeur de l'étudiant 1 ne change pas. long t2 = System.currentTimeMillis(); System.out.println(t2-t1 } }
Cependant, la sérialisation est très chronophage. Dans certains frameworks, on peut sentir qu'ils sérialisent souvent les objets puis les transfèrent, ce qui prend beaucoup de temps.