对象参考更改原始对象

  • 本文关键字:对象 原始 参考 kotlin
  • 更新时间 :
  • 英文 :

class Adult: Resident {
    constructor(name: String, id:String): super(name, id)
    var email: String? = null
    var address: MutableList<String>? = null
    fun setAddress(s: String){
        address = s.split("\n".toRegex()).toMutableList()
    }
}

,这是该测试案例的失败,因为

b.address = a.addressb.address?.add("Universe"(也将添加到对象a中。

fun test6() {
    val a = Adult("Roger Widdoff","604119274")
    val b = Adult("Kathleen Craig","647022192")
    a.setAddress("123 Main StreetnAnytown, Country")
    assertEquals(2,a.address?.size)
    b.address = a.address
    b.address?.add("Universe")
    assertEquals(3,b.address?.size)
    assertEquals(2,a.address?.size)
}

我真的很困惑为什么会发生这种情况,并且我已经搜索了数小时的文档。谁能将我链接到某个地方来解决这个问题?谢谢。

使用 b.address = a.address,您正在创建一个指向现有对象实例的变量(将其作为指向存储的内存的指针(。它不是创建副本。结果,您有两个变量b.addressa.address指向同一对象,即MutableList<String>的实例。无论您使用哪种变量,对此情况进行的任何更改都将在它们中看到。

这不是Kotlin的"特征",它是一个普遍的概念,被描述为混音:

在计算中,混叠描述了一个情况,在这种情况下,可以通过程序中的不同符号名称访问内存中的数据位置。因此,通过一个名称修改数据会隐式修改与所有别名名称关联的值,程序员可能不会期望。

通常,我建议将您的列表类型更改为ReadOnly List,这首先避免了此错误的测试用例。由于您无法修改测试案例,因此可以使用自定义Getter来处理该问题,该getter创建列表的副本:

var address: MutableList<String>? = null
    get () = field?.toMutableList()

如果要在b.address = a.address上"复制",则应避免使用mutableList。而是使用immutable一个:

class Adult {
    constructor(name: String, id: String)
    var email: String? = null
    var address: List<String> = emptyList()
    fun setAddress(s: String) {
        address = s.split("\n".toRegex()).toMutableList()
    }
}

class AdultTest {
    @Test
    fun test6() {
        val a = Adult("Roger Widdoff","604119274")
        val b = Adult("Kathleen Craig","647022192")
        a.setAddress("123 Main StreetnAnytown, Country")
        assertEquals(2,a.address.size)
        b.address = a.address
        b.address += "Universe"
        assertEquals(3,b.address.size)
        assertEquals(2,a.address.size)
    }
}

在这里,您将address作为不可变的列表。首先,用b.address = a.address复制它,只需指向同一列表。但是b.address += "Universe"然后仅更改b

的列表

最新更新