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.address
, b.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.address
和a.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