In Kotlin, shallow copy (oppervlakkige kopie) creëert een nieuw object, maar geneste objecten (bijvoorbeeld elementen van collecties of referentievelden) worden niet gekopieerd, maar verwijzen naar dezelfde objecten als het originele exemplaar. Deep copy (diepe kopie) betekent het recursief kopiëren van alle geneste objecten (objectgrafiek), zodat het origineel en de kopie volledig onafhankelijk zijn.
In de standaard bibliotheek van Kotlin is er geen universeel middel voor diepe kopieën, en dit moet handmatig worden geïmplementeerd, vooral voor complexe structuren of grafieken met cycli.
data class Person(val name: String, val addresses: List<String>) val original = Person("Anna", listOf("Moscow", "London")) val shallow = original.copy() println(original.addresses === shallow.addresses) // true, dezelfde referentie
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, nieuwe kopie van de lijst
Als je
.copy()gebruikt voor een data class met geneste collecties, worden de collecties dan gekopieerd? Waarom?
Nee, copy() maakt een oppervlakkige kopie. Geneste collecties en objecten blijven verwijzingen naar dezelfde objecten. Elke wijziging in deze objecten zal zichtbaar zijn in zowel het origineel als de kopie, wat kan leiden tot bugs.
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] — het origineel is gewijzigd!
Verhaal
In een project werd de staat van een object opgeslagen via de gewone
.copy()van een data class, in de veronderstelling dat we een "snapshot" kregen. Toen we terugkeerden naar de oude staat, bleek dat de geneste lijst (mutableList) in alle kopieën was gewijzigd door de oppervlakkige kopie.
Verhaal
In het documentensysteem werden entiteiten gekopieerd via serialisatie/deserialisatie met Gson, in de verwachting een diepe kopie te krijgen, maar nullable velden en datums werden verkeerd geserialiseerd — als gevolg hiervan verschenen er onjuiste waarden en fouten in de bedrijfslogica.
Verhaal
Bij het migreren van de staat in een Redux-achtige store voor Android-ontwikkeling werd
copy()gebruikt voor state-bomen, in de verwachting dat de kopieën volledig onafhankelijk waren. Uiteindelijk kon een tak van de store de staat van een andere tak muteren vanwege verwijzingen naar dezelfde interne mutable-collecties.