Shallow copy (flaches Kopieren) erstellt ein neues Objekt, kopiert jedoch nur die Referenzen auf die eingebetteten Objekte und nicht die Objekte selbst. Deep copy (tiefes Kopieren) erstellt ein neues Objekt und kopiert rekursiv alle Objekte, die in das ursprüngliche eingebettet sind, sodass zwischen der Kopie und dem Original keine gemeinsamen Referenzen bestehen.
Wann verwenden:
Beispielimplementation:
// Beispiel einer Klasse mit einem eingebetteten Objekt 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)); } }
Kann man deep copy mit der Methode clone() implementieren?
Antwort:
Nein, die Standardmethode Object.clone() implementiert nur "shallow copy". Um deep copy zu erhalten, muss man entweder alle eingebetteten Felder manuell klonen oder externe Bibliotheken (z.B. Apache Commons Lang) verwenden.
Beispiel:
@Override public Person clone() throws CloneNotSupportedException { Person cloned = (Person) super.clone(); cloned.address = new Address(this.address.city); // manuelles deep copy return cloned; }
Geschichte
In einem großen CRM-Projekt erwartete der Entwickler nach der Implementierung des Kopierens von Objekten über
super.clone(), dass die Kopien völlig unabhängig wären, aber als die Adresse des kopierten Benutzers geändert wurde, änderte sich auch die Adresse des Originals. Der Bug wurde erst nach dem Release entdeckt und führte zu Verwirrung in der Kundendatenbank.
Geschichte
Bei der Serialisierung/Deserialisierung wurde für das tiefe Kopieren der Standardmechanismus Serializable gewählt. Es wurde jedoch vergessen, eines der Felder des eingebetteten Objekts als Serializable zu deklarieren, was zu Fehlern während des Betriebs (NotSerializableException) und Datenverlusten bei Backups führte.
Geschichte
In einem der Mikrodienste wurde die Bibliothek BeanUtils.copyProperties zum Kopieren von DTO verwendet, ohne sich darüber im Klaren zu sein, dass der Mechanismus nur shallow copy implementiert. Nach der Refaktorisierung traten viele unauffällige Bugs auf, bei denen Änderungen an eingebetteten Sammlungen die Originaldaten, die aus der Datenbank abgefragt wurden, beeinflussten.