Shallow copy crea un nuovo oggetto, ma copia riferimenti agli oggetti annidati, anziché gli oggetti stessi. Deep copy crea un nuovo oggetto e copia ricorsivamente tutti gli oggetti annidati nell'oggetto originale, in modo che non ci siano riferimenti condivisi tra la copia e l'originale.
Quando utilizzare:
Esempio di implementazione:
// Esempio di classe con oggetto annidato 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)); } }
È possibile implementare deep copy utilizzando il metodo clone()?
Risposta:
No, il metodo standard Object.clone() implementa solo "shallow copy". Per ottenere deep copy, è necessario clonare manualmente tutti i campi annidati o utilizzare librerie di terze parti (ad esempio, Apache Commons Lang).
Esempio:
@Override public Person clone() throws CloneNotSupportedException { Person cloned = (Person) super.clone(); cloned.address = new Address(this.address.city); // deep copy manuale return cloned; }
Storia
In un grande progetto CRM, dopo aver implementato la copia degli oggetti tramite
super.clone(), lo sviluppatore si aspettava una completa indipendenza delle copie, ma modificando l'indirizzo di un utente copiato, cambiava anche l'indirizzo dell'originale. Il bug è stato scoperto solo dopo il rilascio e ha causato confusione nel database clienti.
Storia
Durante la serializzazione/deserializzazione per la copia profonda, è stato scelto il meccanismo standard Serializable. Tuttavia, è stato dimenticato di dichiarare uno dei campi dell'oggetto annidato come Serializable, il che ha portato a errori durante l'esecuzione (NotSerializableException) e perdite di dati durante il backup.
Storia
In uno dei microservizi è stata utilizzata la libreria BeanUtils.copyProperties per copia DTO, senza rendersi conto che il meccanismo implementa solo shallow copy. Dopo il refactoring, sono emersi numerosi bug non evidenti, quando la modifica delle collezioni annidate influenzava i dati originali ottenuti dal database.