如果我clear()
我的本地列表(mList
),它也会清除companion
的可变列表(list
) 为什么这种发生的解释是受欢迎的:)
我有一个这样的companion
课:
class Data {
companion object {
var list:MutableList<String> = ArrayList()
}
}
如果我创建我的本地列表,如下所示:
fun main() {
// some dummy data
Data.list.add("Lion")
Data.list.add("Cat")
Data.list.add("Dog")
Data.list.add("Cheetah")
// my local mList
val mList = Data.list
println("Before Clearing : mList = $mListn list = ${Data.list}")
mList.clear()
println("After Clearing : mList = $mListn list = ${Data.list}")
}
输出
Before Clearing : mList = [Lion, Cat, Dog, Cheetah]
list = [Lion, Cat, Dog, Cheetah]
After Clearing : mList = []
list = []
正如您在输出中看到的那样,如果我clear()
本地mList
它正在清除companion
的列表为什么是?
如果我对其他一些事情做同样的事情,比如double
它不会像这个例子那样发生——
// same Data class's
...
var pi = 3.14
...
如果更改本地mPi
它不会更改pi
:
var mPi = Data.pi
println("Before Assigning to New value mPi = $mPi and pi = ${Data.pi}")
mPi = 319.12
println("After Assigning to New value mPi = $mPi and pi = ${Data.pi}")
第二路输出
Before Assigning to New value mPi = 3.14 and pi = 3.14
After Assigning to New value mPi = 319.12 and pi = 3.14
科特林游乐场链接
为什么会这样?我想知道:)
为了理解这里发生了什么,你需要知道值是如何保存在内存中的。使用new
关键字创建的所有对象(在 Kotlin 中不需要)都存储在堆内存中,而所有基元数据类型都存储在堆栈内存中。
请考虑以下代码
val list: MutableList<String> = ArrayList()
这里发生的事情是在堆中创建一个新的ArrayList
对象。变量list
可以被视为一个框,其中包含创建实际对象的位置。您可以想象变量的值为0x7800abd12
。
现在,当您创建一个新变量并分配您在上面创建的变量时,会发生什么。
val newList = list
在这里,您将变量list
具有的任何值分配给变量newList
。这实际上是将内存地址0x7800abd12
保存在变量newList
中。请记住,该值是创建实际列表的位置。现在,如果用户访问list
或newList
,他们将被带到给定内存地址的对象。由于两个变量具有相同的地址,因此对两个变量中的任何一个所做的任何更改都将反映在这两个变量中。
但是为什么当我们使用原始数据类型时,这种行为没有反映出来。请记住,我提到过原始数据类型存储在堆栈而不是堆上。考虑这个例子
val pi = 3.142
在这种情况下,变量pi
实际上保存值3.142
而不是内存位置。现在,当您将其分配给另一个变量时,新变量也会保存该值而不是内存位置。
val newPi = pi
在这里newPi
保存值3.142
。如果将newPi
更改为其他值,则只会更新变量newPi
,而不会更新变量pi
。
为了了解更多信息,您可以查看此线程。
您将更改列表的内容与更改变量的值进行了比较,这两者不是一回事。在您的示例中,首先将mPi
指定为指向Data.pi
的值,然后将其更改为指向其他某个 Double。您没有做任何事情来修改 Double 本身,只做局部变量mPi
指向的内容。
执行val newList = Data.list
时,将变量声明为指向与 Data 中相同的列表实例。然后修改同一列表的内容。由于两个变量都指向同一个实例,因此如果通过任一变量检查实例,您将观察到相同的变化。 请注意,您没有像在pi
示例中那样使用newList =
重新分配变量的值,这就是为什么这些不是类似操作的原因。
简而言之,在 pi 示例中,您有两个 Double 实例,并通过更改变量的值在它们之间切换。对于列表示例,您只有一个在内部进行变异的 MutableList 实例。
值得注意的是,基元类型类都是不可变的,因此即使您愿意,也无法修改它们的内容。它们没有函数,您可以调用它们来更改它们所代表的值。在 Kotlin 中,你很少需要考虑基元类和其他类之间的区别,除非你要优化代码性能。