首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Kotlin数据类复制方法不深入复制所有成员

Kotlin数据类复制方法不深入复制所有成员
EN

Stack Overflow用户
提问于 2017-11-17 21:23:26
回答 10查看 71.2K关注 0票数 70

有人能解释一下Kotlin数据类的copy方法到底是如何工作的吗?对于一些成员来说,实际上并没有创建一个(深)副本,而且引用仍然是原始的。

代码语言:javascript
运行
复制
fun test() {
    val bar = Bar(0)
    val foo = Foo(5, bar, mutableListOf(1, 2, 3))
    println("foo    : $foo")

    val barCopy = bar.copy()
    val fooCopy = foo.copy()
    foo.a = 10
    bar.x = 2
    foo.list.add(4)

    println("foo    : $foo")
    println("fooCopy: $fooCopy")
    println("barCopy: $barCopy")
}

data class Foo(var a: Int,
               val bar: Bar,
               val list: MutableList<Int> = mutableListOf())

data class Bar(var x: Int = 0)

输出: foo : Foo(a=5,bar=Bar(x=0),list=1,2,3) foo : Foo(a=10,bar=Bar(x=2),list=1,2,3,4) fooCopy: Foo(a=5,bar=Bar(x=2),list=1,2,3,4) barCopy: Bar(x=0)

为什么是barCopy.x=0 (预期),但是fooCopy.bar.x=2 (我认为应该是0)。因为Bar也是一个数据类,所以在执行foo.copy()时,foo.bar也是一个副本。

为了深入复制所有成员,我可以这样做:

代码语言:javascript
运行
复制
val fooCopy = foo.copy(bar = foo.bar.copy(), list = foo.list.toMutableList())

fooCopy: Foo(a=5,bar=Bar(x=0),list=1,2,3)

但是,我是否遗漏了一些东西,或者是否有更好的方法来做到这一点,而无需具体说明这些成员需要强制提交一份深刻的副本?

EN

回答 10

Stack Overflow用户

回答已采纳

发布于 2017-11-18 00:27:57

Kotlin的copy方法根本不应该是一个深拷贝。正如参考文档(https://kotlinlang.org/docs/reference/data-classes.html)中所解释的那样,对于一个类,如:

代码语言:javascript
运行
复制
data class User(val name: String = "", val age: Int = 0)

copy的实现将是:

代码语言:javascript
运行
复制
fun copy(name: String = this.name, age: Int = this.age) = User(name, age)

所以正如你所看到的,这是一个浅薄的复制品。在特定情况下,copy的实现应该是:

代码语言:javascript
运行
复制
fun copy(a: Int = this.a, bar: Bar = this.bar, list: MutableList<Int> = this.list) = Foo(a, bar, list)

fun copy(x: Int = this.x) = Bar(x)
票数 67
EN

Stack Overflow用户

发布于 2017-11-18 09:57:41

正如@Ekeko所说,为数据类实现的默认copy()函数是一个浅表副本,如下所示:

代码语言:javascript
运行
复制
fun copy(a: Int = this.a, bar: Bar = this.bar, list: MutableList<Int> = this.list)

要执行深度复制,必须重写copy()函数。

代码语言:javascript
运行
复制
fun copy(a: Int = this.a, bar: Bar = this.bar.copy(), list: MutableList<Int> = this.list.toList()) = Foo(a, bar, list)
票数 12
EN

Stack Overflow用户

发布于 2019-01-12 08:36:21

有一种方法可以在Kotlin (和Java)中对对象进行深度复制:将其序列化为内存,然后反序列化它回到一个新对象。这只有在对象中包含的所有数据都是原语或实现可序列化接口时才能工作。

下面是使用示例Kotlin代码https://rosettacode.org/wiki/Deepcopy#Kotlin的说明

代码语言:javascript
运行
复制
import java.io.Serializable
import java.io.ByteArrayOutputStream
import java.io.ByteArrayInputStream
import java.io.ObjectOutputStream
import java.io.ObjectInputStream

fun <T : Serializable> deepCopy(obj: T?): T? {
    if (obj == null) return null
    val baos = ByteArrayOutputStream()
    val oos  = ObjectOutputStream(baos)
    oos.writeObject(obj)
    oos.close()
    val bais = ByteArrayInputStream(baos.toByteArray())
    val ois  = ObjectInputStream(bais)
    @Suppress("unchecked_cast")
    return ois.readObject() as T
} 

注意:这个解决方案也应该适用于Android,使用Parcelable界面而不是Serializable。Parcelable更有效。

票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47359496

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档