tri*_*iad 16 copy deep-copy kotlin data-class
有人可以解释copyKotlin数据类的方法究竟是如何工作的吗?对于某些成员来说,实际上并没有创建(深层)副本,并且引用仍然是原始的.
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)
Run Code Online (Sandbox Code Playgroud)
输出:
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.bar在foo.copy()执行时也是一个副本.
要深刻复制所有成员,我可以这样做:
val fooCopy = foo.copy(bar = foo.bar.copy(), list = foo.list.toMutableList())
Run Code Online (Sandbox Code Playgroud)
fooCopy:Foo(a = 5,bar = Bar(x = 0),list = [1,2,3])
但我是否遗漏了某些东西,或者是否有更好的方法来做到这一点,而无需指定这些成员需要强制进行深层复制?
Eke*_*eko 32
copyKotlin 的方法根本不应该是一个很深的副本.如参考文档(https://kotlinlang.org/docs/reference/data-classes.html)中所述,对于如下类的类:
data class User(val name: String = "", val age: Int = 0)
Run Code Online (Sandbox Code Playgroud)
的copy实现将是:
fun copy(name: String = this.name, age: Int = this.age) = User(name, age)
Run Code Online (Sandbox Code Playgroud)
所以你可以看到,这是一个浅薄的副本.的实现copy在你的具体情况是:
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)
Run Code Online (Sandbox Code Playgroud)
当心那些只是将列表引用从旧对象复制到新对象的答案。我发现的唯一快速深度复制方法是序列化/反序列化对象,即将对象转换为 JSON,然后将它们转换回 POJO。如果您使用的是 GSON,这里是一段代码:
class Foo {
fun deepCopy() : Foo {
return Gson().fromJson(Gson().toJson(this), this.javaClass)
}
}
Run Code Online (Sandbox Code Playgroud)
小智 5
正如@Ekeko所说,copy()为数据类实现的默认函数是一个浅表副本,看起来像这样:
fun copy(a: Int = this.a, bar: Bar = this.bar, list: MutableList<Int> = this.list)
Run Code Online (Sandbox Code Playgroud)
要执行深层复制,您必须覆盖该copy()功能。
fun copy(a: Int = this.a, bar: Bar = this.bar.copy(), list: MutableList<Int> = this.list.toList()) = Foo(a, bar, list)
Run Code Online (Sandbox Code Playgroud)
有一种方法可以在Kotlin(和Java)中复制对象的深层副本:将其序列化到内存中,然后反序列化回新的对象。仅当对象中包含的所有数据都是原语或实现Serializable接口时,这才起作用
这是示例Kotlin代码的说明https://rosettacode.org/wiki/Deepcopy#Kotlin
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
}
Run Code Online (Sandbox Code Playgroud)
注意:此解决方案也应适用于使用Parcelable接口而非Serializable接口的Android。可打包的效率更高。
| 归档时间: |
|
| 查看次数: |
16548 次 |
| 最近记录: |