编程Kotlin开发人员

解释Kotlin中浅拷贝和深拷贝之间的区别。如何实现对象的深度复制,以及在复制复杂结构时常见的错误是什么?

用 Hintsage AI 助手通过面试

答案。

在Kotlin中,浅拷贝 创建了一个新对象,但嵌套对象(如集合元素或引用字段)并没有被复制,而是引用同样的对象,如原始实例。深拷贝 意味着递归复制所有嵌套对象(对象图),使得原始对象和副本完全独立。

在Kotlin的标准库中,没有通用的深拷贝工具,尤其是对于复杂结构或循环图,必须手动实现。

浅拷贝示例:

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, 是同一个引用

深拷贝示例:

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, 列表的新副本

反向问题。

如果对嵌套集合的data class使用.copy(),集合会被复制吗?为什么?

带示例的答案:

不,copy()创建了一个浅拷贝。嵌套集合和对象仍然引用相同的对象。对这些对象的任何修改都会在原始对象和副本中可见,这可能导致bug。

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] — 原始对象也被修改了!

由于对主题细节的不了解而导致的实际错误示例。


故事

在一个项目中,通过普通的.copy() data class保存对象状态,认为得到了一个"快照"。当返回到旧状态时,发现嵌套列表(mutableList)由于浅拷贝而在所有副本中被更改。


故事

在文档系统中,通过Gson的序列化/反序列化复制实体,期待深度复制,但nullable字段和日期序列化不正确,导致出现不正确的值和业务逻辑错误。


故事

在将状态迁移到类似Redux的Android开发store时,开始对状态树使用copy(),期待副本完全独立。结果,一条store分支可能会由于引用相同的内部mutable集合而改变另一条状态。