You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin派生类属性初始化问题:为何输出nullnullnull而非预期值

Kotlin属性初始化问题解析:为什么输出nullnullnull,改函数却正常?

一、为什么代码输出"nullnullnull"?

核心原因是Kotlin类的初始化顺序和open属性的访问时机:

  1. 创建Derived实例时,会优先执行基类Base的构造逻辑。
  2. Base中的concatenation是在构造阶段完成初始化的,此时它会读取a、b、c的属性值。
  3. 但a、b、c是被Derived重写的open属性,而派生类的属性初始化是在基类构造完成后才执行的——此时Derived的a、b、c还没被赋值为"foo"/"bar"/"baz",作为引用类型的String,默认值是null。
  4. 最终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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 06:12:20