Kotlin中从类字段赋值的变量为何在函数内不会随原字段变更?
为什么类字段赋值给局部变量后,原字段变更不会影响该局部变量?
这个问题的核心其实是理解Kotlin中赋值操作的本质,以及局部变量的特性,咱们一步步拆解:
1. 局部变量b的取值只在赋值那一刻确定
你代码里的val b = a,本质是把当前时刻字段a的值复制给了局部变量b。这里要明确:
- 如果
a是基本类型(比如Int),复制的就是具体的数值; - 如果
a是引用类型(比如String、自定义类),复制的是对象的引用地址(但这不是“绑定”,只是把地址值拷贝给b)。
一旦赋值完成,b就和原字段a彻底解绑了——a后续的任何变更(不管是重新赋值指向新对象,还是被并发修改),都不会影响b存储的值。
2. 编译器智能转换的依据
编译器之所以能在if (b != null)分支里把b视为非空,是因为b是函数内的val局部变量:在函数执行期间,没有任何代码能修改b的值(Kotlin的val是只读的,局部val更是无法被外部线程修改)。这个判断和原字段a是否被修改完全无关,只看b自己的特性。
3. 并发场景下的表现
即使有其他线程在val b = a之后修改了字段a,函数里的b也不会发生变化:
- 局部变量
b存储在当前线程的栈帧中,其他线程无法直接修改它; a的修改只是改变了类实例中的字段值(比如让它指向新的String对象),但b已经保存了赋值那一刻的引用地址,不会同步更新。
4. 引用类型的特殊情况(容易混淆的点)
你提到“原以为赋值是通过引用实现的”,这里要区分两种情况:
- 如果是修改对象内部的可变属性(比如自定义类的
var字段):
这种情况看起来class MyData(var count: Int) class A { private var a: MyData? = MyData(0) fun hello() { val b = a // 其他线程修改a?.count = 100 println(b?.count) // 会输出100,因为b和a指向同一个对象 } }b跟着变了,但本质不是b的值变了,而是b指向的对象内部状态变了,b的引用地址还是原来的那个。 - 如果是给
a重新赋值指向新对象(比如你的例子里a = "new value"):
此时b还是指向原来的"a"对象,完全不受影响。
总结一下
- 局部
val变量一旦赋值,其值(基本类型的数值、引用类型的地址)就固定了,和原字段不再有任何关联; - 编译器对
b的非空智能转换,是基于局部val不可变的特性,和原字段a的状态无关; - 并发修改原字段不会改变局部变量
b的值,因为b的取值只在赋值瞬间被确定。
内容的提问来源于stack exchange,提问作者Pedro Romano Barbosa




