ProgramaciónDesarrollador Kotlin

Explique la diferencia entre shallow copy y deep copy en Kotlin. ¿Cómo implementar la copia profunda de objetos y cuáles son los errores típicos al copiar estructuras complejas?

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

En Kotlin, shallow copy (copia superficial) crea un nuevo objeto, pero los objetos anidados (por ejemplo, elementos de colecciones o campos de referencia) no se copian, sino que hacen referencia a los mismos objetos que el objeto original. Deep copy (copia profunda) significa copiar recursivamente todos los objetos anidados (el gráfico de objetos), de modo que el original y la copia sean completamente independientes.

No hay una herramienta universal en la biblioteca estándar de Kotlin para la copia profunda, y debe implementarse manualmente, especialmente para estructuras complejas o gráficos con ciclos.

Ejemplo de copia superficial:

data class Person(val name: String, val addresses: List<String>) val original = Person("Anna", listOf("Moscú", "Londres")) val shallow = original.copy() println(original.addresses === shallow.addresses) // true, la misma referencia

Ejemplo de copia profunda:

data class Person(val name: String, val addresses: List<String>) { fun deepCopy(): Person = Person(name, addresses.toList()) } val deep = original.deepCopy() printfn(original.addresses === deep.addresses) // false, nueva copia de la lista

Pregunta capciosa.

Si se usa .copy() para un data class con colecciones anidadas, ¿se copiarán las colecciones? ¿Por qué?

Respuesta con ejemplo:

No, copy() crea una copia superficial. Las colecciones anidadas y los objetos seguirán siendo referencias a los mismos objetos. Cualquier cambio en estos objetos será visible tanto en el original como en la copia, lo que puede provocar errores.

data class Box(val items: MutableList<String>) val box1 = Box(mutableListOf("A")) val box2 = box1.copy() box2.items.add("B") printfn(box1.items) // [A, B] — ¡se modificó el original!

Ejemplos de errores reales debido al desconocimiento de los matices del tema.


Historia

En un proyecto, se guardó el estado de un objeto a través del .copy() normal de un data class, creyendo que obtenían una "instantánea". Al volver a un estado anterior, resultó que la lista anidada (mutableList) había sido modificada en todas las copias debido a la copia superficial.


Historia

En un sistema de documentos, se copiaron entidades a través de la serialización/deserialización usando Gson, esperando una copia profunda, pero los campos anulables y las fechas se serializaban incorrectamente, lo que resultaba en valores incorrectos y errores en la lógica de negocio.


Historia

Al migrar el estado en un store similar a Redux para el desarrollo de Android, comenzaron a usar copy() para árboles de estado, esperando completa independencia de las copias. Al final, una rama del store podía mutar el estado de otra debido a referencias a las mismas colecciones mutables internas.