ProgrammationDéveloppeur Java

Expliquez la différence entre shallow copy et deep copy des objets en Java. Comment peuvent-ils être implémentés et dans quelles situations est-il important de comprendre cette différence ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

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.

Exemple de shallow copy (via clone)

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

Exemple de deep copy

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 piège.

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.

Exemples d'erreurs réelles dues à l'ignorance des subtilités du sujet.


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.