Shallow copy (copie superficielle) crée un nouvel objet, mais copie les références aux objets imbriqués, et non les objets eux-mêmes. Deep copy (copie profonde) crée un nouvel objet et copie de manière récursive tous les objets imbriqués dans l'original, de sorte qu'il n'y a pas de références partagées entre la copie et l'original.
Quand utiliser :
Exemple d'implémentation :
// Exemple de classe avec un objet imbriqué class Address { String city; Address(String city) { this.city = city; } } class Person implements Cloneable { String name; Address address; Person(String name, Address address) { this.name = name; this.address = address; } // Shallow copy public Person clone() throws CloneNotSupportedException { return (Person) super.clone(); } // Deep copy public Person deepClone() { return new Person(this.name, new Address(this.address.city)); } }
Peut-on réaliser un deep copy en utilisant la méthode clone() ?
Réponse :
Non, la méthode standard Object.clone() ne réalise qu'une "shallow copy". Pour obtenir une deep copy, il faut soit cloner manuellement tous les champs imbriqués, soit utiliser des bibliothèques tierces (par exemple, Apache Commons Lang).
Exemple :
@Override public Person clone() throws CloneNotSupportedException { Person cloned = (Person) super.clone(); cloned.address = new Address(this.address.city); // deep copy manuelle return cloned; }
Histoire
Dans un grand projet CRM, après avoir implémenté le clonage d'objets via
super.clone(), le développeur s'attendait à l'indépendance complète des copies, mais en modifiant l'adresse de l'utilisateur cloné, l'adresse de l'original changeait également. Le bug a été identifié après la publication et a causé de la confusion dans la base de clients.
Histoire
Lors de la sérialisation/désérialisation pour le clonage profond, le mécanisme standard Serializable a été choisi. Cependant, un des champs d'un objet imbriqué a été oublié d'être déclaré comme Serializable, ce qui a conduit à des erreurs pendant l'exécution (NotSerializableException) et des pertes de données lors de la sauvegarde.
Histoire
Dans l'un des microservices, ils ont utilisé la bibliothèque de clonage BeanUtils.copyProperties pour copier des DTO, sans réaliser que le mécanisme ne réalise qu'une shallow copy. Après le refactoring, il y a eu de nombreux bugs non évidents lorsque les modifications des collections imbriquées affectaient les données originales obtenues de la base.