ProgrammierungKotlin-Entwickler

Erklären Sie den Unterschied zwischen shallow copy und deep copy in Kotlin. Wie realisiert man eine tiefgehende Kopie von Objekten und was sind typische Fehler beim Kopieren komplexer Strukturen?

Bestehen Sie Vorstellungsgespräche mit dem Hintsage-KI-Assistenten

Antwort.

In Kotlin erstellt shallow copy (flaches Kopieren) ein neues Objekt, aber die eingebetteten Objekte (z.B. Elemente in Sammlungen oder Referenzfelder) werden nicht kopiert, sondern verweisen auf dieselben Objekte wie das ursprüngliche Exemplar. Deep copy (tiefes Kopieren) bedeutet rekursives Kopieren aller eingebetteten Objekte (Objektgraph), so dass das Original und die Kopie vollständig unabhängig sind.

In der Standardbibliothek von Kotlin gibt es kein universelles Mittel für tiefes Kopieren, und es muss manuell implementiert werden, insbesondere für komplexe Strukturen oder Graphen mit Zyklen.

Beispiel für flaches Kopieren:

data class Person(val name: String, val addresses: List<String>) val original = Person("Anna", listOf("Moskau", "London")) val shallow = original.copy() println(original.addresses === shallow.addresses) // true, dieselbe Referenz

Beispiel für tiefes Kopieren:

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, neue Kopie der Liste

Fangfrage.

Wird copy() für data class mit eingebetteten Sammlungen verwendet, werden die Sammlungen kopiert? Warum?

Antwort mit Beispiel:

Nein, copy() erstellt eine flache Kopie. Eingebettete Sammlungen und Objekte bleiben Referenzen auf dieselben Objekte. Änderungen an diesen Objekten sind sowohl im Original als auch in der Kopie sichtbar, was zu Bugs führen kann.

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] — auch das Original wurde verändert!

Beispiele für echte Fehler aufgrund mangelnden Wissens über die Feinheiten des Themas.


Geschichte

In einem Projekt wurde der Zustand eines Objekts mittels des normalen .copy() der data class gespeichert, in dem Glauben, einen "Schnappschuss" zu erhalten. Bei der Rückkehr zu einem alten Zustand stellte sich heraus, dass die eingebettete Liste (mutableList) in allen Kopien aufgrund des flachen Kopierens geändert worden war.


Geschichte

Im Dokumentensystem wurden Entitäten durch Serialisierung/Deserialisierung mit Gson kopiert, in der Erwartung, ein tiefes Kopieren zu erhalten, aber nullable Felder und Daten wurden falsch serialisiert — in der Folge traten inkorrekte Werte und Geschäftslogikfehler auf.


Geschichte

Bei der Migration des Zustands in einem Redux-ähnlichen Store für die Android-Entwicklung wurde copy() für Zustandsbäume verwendet, in der Erwartung vollständiger Unabhängigkeit der Kopien. Letztendlich konnte ein Ast des Stores den Zustand eines anderen aufgrund von Referenzen auf dieselben internen mutierbaren Sammlungen verändern.