Kotlin派生类属性初始化问题:为何输出nullnullnull而非预期值
Kotlin属性初始化问题解析:为什么输出nullnullnull,改函数却正常?
一、为什么代码输出"nullnullnull"?
核心原因是Kotlin类的初始化顺序和open属性的访问时机:
- 创建
Derived实例时,会优先执行基类Base的构造逻辑。 Base中的concatenation是在构造阶段完成初始化的,此时它会读取a、b、c的属性值。- 但
a、b、c是被Derived重写的open属性,而派生类的属性初始化是在基类构造完成后才执行的——此时Derived的a、b、c还没被赋值为"foo"/"bar"/"baz",作为引用类型的String,默认值是null。 - 最终
concatenation拼接了三个null,所以输出"nullnullnull"。
IDEA提示的含义
你看到的Accessing non-final property <property> in constructor警告,意思是:在基类构造器中访问了被标记为open的非final属性。这类属性允许被派生类重写,但基类构造执行时派生类还未完成初始化,此时访问该属性会拿到派生类中未初始化的默认值,极易引发意外错误,因此IDEA会给出这个风险提示。
二、把concatenation改成函数后为什么正常?
如果把Base中的val concatenation改成函数,比如:
open class Base( open val a: String, open val b: String, open val c: String, ) { fun concatenation() = a + b + c }
函数concatenation()不会在构造阶段执行,而是在你主动调用它时(也就是main里的println(derived.concatenation()))才会读取a、b、c的值。这时Derived实例已经完全初始化完成,a、b、c已经被赋值为目标字符串,自然能得到正确的拼接结果"foobarbaz"。
总结
本质是初始化时机的差异:
- 类的属性初始化是在构造阶段执行的,基类构造先于派生类属性初始化,此时访问被重写的open属性会拿到未初始化的默认值。
- 函数是按需调用的,调用时整个实例已经完成初始化,能正确获取到派生类中已赋值的属性值。
内容的提问来源于stack exchange,提问作者user25583367
相关产品推荐
相关产品推荐

