En Java, la shallow copy (copie superficielle) est la copie d'un objet où seules les références aux objets imbriqués sont copiées et non les objets eux-mêmes. Ainsi, les modifications apportées aux objets imbriqués se refléteront dans la copie et dans l'original. La deep copy (copie profonde) implique la création de nouvelles copies indépendantes de tous les objets imbriqués.
class Address implements Cloneable { String city; Address(String city) { this.city = city; } protected Object clone() throws CloneNotSupportedException { return super.clone(); } } class Person implements Cloneable { String name; Address address; Person(String name, Address address) { this.name = name; this.address = address; } protected Object clone() throws CloneNotSupportedException { return super.clone(); } } // Utilisation Person p1 = new Person("Ivan", new Address("Moscow")); Person p2 = (Person) p1.clone(); p2.address.city = "Petersburg"; System.out.println(p1.address.city); // Affichera "Petersburg" — copie superficielle
class Address implements Cloneable { String city; Address(String city) { this.city = city; } protected Object clone() throws CloneNotSupportedException { return new Address(this.city); } } class Person implements Cloneable { String name; Address address; Person(String name, Address address) { this.name = name; this.address = address; } protected Object clone() throws CloneNotSupportedException { Person cloned = (Person) super.clone(); cloned.address = (Address) address.clone(); return cloned; } }
La copie profonde permet de créer une copie complètement indépendante de l'objet.
Question : Peut-on utiliser la méthode clone() pour garantir une copie profonde d'un objet complexe arbitraire ?
Réponse : Non, la méthode clone() standard ne fait qu'une copie superficielle. Pour une copie profonde, il est nécessaire de redéfinir clone() dans toutes les classes imbriquées et de cloner explicitement tous les champs de référence. De plus, de nombreuses collections et classes standard ne prennent pas en charge le clonage profond.
Histoire
La collection d'utilisateurs et leurs adresses ont été clonées par la méthode clone() sans copie profonde. Après modification de l'adresse d'un utilisateur, l'adresse de l'autre a également changé, car la référence était copiée. Les données dans la base ont "fui" entre les utilisateurs.
Histoire
Lors de la sérialisation d'un objet complexe avec des collections imbriquées, clone() a été utilisé au lieu d'une copie profonde. Après restauration de la sérialisation, les données se sont révélées incohérentes et des NPE se sont produits.
Histoire
Dans les API REST, les objets DTO étaient clonés par défaut via BeanUtils.copyProperties(), ce qui entraînait une partage de la même collection entre clients. En conséquence, l'utilisateur pouvait voir et éditer les données d'autrui.