In Java, shallow copy (copia superficiale) è la copia di un oggetto in cui vengono copiate solo le riferimenti agli oggetti annidati, e non gli oggetti stessi. Pertanto, le modifiche agli oggetti annidati si rifletteranno sia nella copia che nell'originale. Deep copy (copia profonda) implica la creazione di nuove copie indipendenti di tutti gli oggetti annidati.
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(); } } // Utilizzo Person p1 = new Person("Ivan", new Address("Mosca")); Person p2 = (Person) p1.clone(); p2.address.city = "Petersburgo"; System.out.println(p1.address.city); // Stampa "Petersburgo" — copia superficiale
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 copia profonda consente di creare una copia completamente indipendente di un oggetto.
Domanda: È possibile utilizzare il metodo clone() per garantire una copia profonda di un oggetto complesso arbitrario?
Risposta: No, il clone() standard esegue solo una copia superficiale (shallow copy). Per la copia profonda è necessario sovrascrivere clone() in tutte le classi annidate e clonare esplicitamente tutti i campi di riferimento. Inoltre, molte collezioni e classi standard non supportano la clonazione profonda.
Storia
Una collezione di utenti e i loro indirizzi è stata clonata utilizzando il metodo clone() senza una copia profonda. Dopo aver modificato l'indirizzo di un utente, anche l'indirizzo di un altro è cambiato perché era stata copiata la referenza. I dati nel database "sono trapelati" tra gli utenti.
Storia
Durante la serializzazione di un oggetto complesso con collezioni annidate è stato utilizzato clone(), invece di una copia profonda. Dopo il ripristino dalla serializzazione, i dati si sono rivelati inconsistenti e si sono verificate NPE.
Storia
Nell'API REST, gli oggetti DTO sono stati clonati per impostazione predefinita tramite BeanUtils.copyProperties(), il che ha portato alla condivisione della stessa collezione tra i client. Di conseguenza, l'utente poteva vedere e modificare i dati di altri.