En Java, shallow copy (copia superficial) es la copia de un objeto donde solo se copian las referencias a los objetos anidados, no los propios objetos. Por lo tanto, los cambios en los objetos anidados se reflejarán tanto en la copia como en el original. Deep copy (copia profunda) implica crear nuevas copias independientes de todos los objetos anidados.
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(); } } // Uso Person p1 = new Person("Ivan", new Address("Moscow")); Person p2 = (Person) p1.clone(); p2.address.city = "Petersburg"; System.out.println(p1.address.city); // Imprimirá "Petersburg" — copia superficial
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 profunda permite crear una copia totalmente independiente del objeto.
Pregunta: ¿Se puede usar el método clone() para garantizar la copia profunda de un objeto complejo arbitrario?
Respuesta: No, el clone() estándar solo hace copia superficial (shallow copy). Para la copia profunda, es necesario sobrescribir clone() en todas las clases anidadas y clonar explícitamente todos los campos de referencia. Además, muchas colecciones y clases estándar no admiten la clonación profunda.
Historia
Una colección de usuarios y sus direcciones fue clonada utilizando el método clone() sin copia profunda. Después de cambiar la dirección de un usuario, la dirección del otro también cambió, porque se copió la referencia. Los datos en la base "fugaron" entre los usuarios.
Historia
Al serializar un objeto complejo con colecciones anidadas, se usó clone(), en lugar de una copia profunda. Tras la restauración de la serialización, los datos resultaron inconsistentes y se produjeron NPE.
Historia
En la API REST, los objetos DTO fueron clonados por defecto a través de BeanUtils.copyProperties(), lo que llevó a compartir la misma colección entre los clientes. Como resultado, un usuario podía ver y editar datos ajenos.