Shallow copy (copia superficial) crea un nuevo objeto, pero copia las referencias a los objetos anidados, no los objetos en sí. Deep copy (copia profunda) crea un nuevo objeto y copia recursivamente todos los objetos anidados en el original, de modo que no hay referencias compartidas entre la copia y el original.
Cuándo usar:
Ejemplo de implementación:
// Ejemplo de clase con objeto anidado 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)); } }
¿Se puede implementar deep copy usando el método clone()?
Respuesta:
No, el método estándar Object.clone() solo implementa "shallow copy". Para obtener deep copy, se debe clonar manualmente todos los campos anidados o usar bibliotecas externas (por ejemplo, Apache Commons Lang).
Ejemplo:
@Override public Person clone() throws CloneNotSupportedException { Person cloned = (Person) super.clone(); cloned.address = new Address(this.address.city); // deep copy manualmente return cloned; }
Historia
En un gran proyecto de CRM, después de implementar la copia de objetos a través de
super.clone(), el desarrollador esperaba una completa independencia de las copias, pero al cambiar la dirección del usuario clonado, también cambiaba la dirección del original. El error se descubrió después del lanzamiento y causó confusión en la base de clientes.
Historia
Durante la serialización/deserialización para copiar profundamente, se eligió el mecanismo estándar Serializable. Sin embargo, se olvidó declarar uno de los campos del objeto anidado como Serializable, lo que resultó en errores durante la ejecución (NotSerializableException) y pérdida de datos en la copia de seguridad.
Historia
En uno de los microservicios, se utilizó la biblioteca BeanUtils.copyProperties para copiar DTO, sin darse cuenta de que el mecanismo solo implementa shallow copy. Después de la refactorización, aparecieron muchos errores no evidentes, cuando los cambios en las colecciones anidadas afectaban los datos originales obtenidos de la base de datos.