ProgrammazioneSviluppatore Java

Spiega le differenze tra shallow copy e deep copy in Java. Come vengono implementate e quando potrebbe essere necessario usarle?

Supera i colloqui con l'assistente IA Hintsage

Risposta

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:

  • Shallow copy è sufficiente se la struttura dell'oggetto non contiene oggetti annidati mutabili, o se non è necessario modificare gli oggetti annidati.
  • Deep copy è necessario se la mutabilità degli oggetti annidati è critica e qualsiasi modifica alla copia non deve riflettersi nell'originale.

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)); } }

Domanda insidiosa

È 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.