Android Kotlin子类参数非空却为null?添加init块恢复正常的原因
问题原因解析:Kotlin类初始化顺序导致的成员变量未初始化问题
这本质是Kotlin父类与子类的初始化执行顺序问题,结合你描述的场景,具体逻辑如下:
核心执行顺序梳理
当创建ComplexSortingButton实例时,代码的执行流程是固定的:
- 先调用父类
SortingButton的构造函数,执行父类的init块。 - 父类
init块中调用onCreate(),此时子类的重写方法会被执行,但子类的成员变量(包括evaluator)还未完成初始化。 - 父类构造全部完成后,才会初始化子类的成员变量(将构造传入的
evaluator参数赋值给成员变量),最后执行子类自己的init块。
对应你的两种场景
场景1:子类无自身init块调用onCreate
此时只有父类init块触发的onCreate调用,这个调用发生在子类evaluator成员变量赋值之前——因为子类成员初始化是父类构造完成后的步骤。所以重写的onCreate里拿到的evaluator是默认的null,哪怕你构造时传了非空值。
对应的简化代码示例:
open class SortingButton(context: Context) : Button(context) { init { onCreate() // 父类init先调用onCreate } open fun onCreate() {} } class ComplexSortingButton(context: Context, val evaluator: Evaluator?) : SortingButton(context) { override fun onCreate() { super.onCreate() println(evaluator) // 此时evaluator还未被赋值,输出null } }
场景2:子类添加init块调用onCreate
子类的init块是在父类构造完成、子类成员变量赋值完成后执行的。此时调用onCreate,evaluator已经被构造参数赋值为非空值,所以重写方法里能拿到正确的非空对象。
对应的简化代码示例:
class ComplexSortingButton(context: Context, val evaluator: Evaluator?) : SortingButton(context) { init { onCreate() // 子类init在成员赋值后调用,此时evaluator已有值 } override fun onCreate() { super.onCreate() println(evaluator) // 输出构造传入的非空值 } }
额外注意
在父类的构造函数或init块中调用可重写的方法是不推荐的危险操作,因为子类此时还未完成初始化,很容易出现这种未初始化成员的问题,甚至引发崩溃。更合理的做法是让子类自行在合适的时机(比如自身init块、Android的onFinishInflate等生命周期方法)调用初始化逻辑,而非依赖父类的提前调用。
内容的提问来源于stack exchange,提问作者Owlon
相关产品推荐
相关产品推荐

