初始化含抽象val的父类子类时出现NPE的原因咨询
Kotlin子类初始化时父类回调访问抽象val引发NPE的原因分析
核心原因:Kotlin类初始化顺序导致属性未完成赋值
Kotlin中类的初始化严格遵循以下顺序:
- 先执行父类的主构造函数,再执行父类的
init块 - 之后才会初始化子类的属性,最后执行子类的
init块
你的代码中,父类SomeSuperClass的init块里注册了回调,若SomeManager立即触发onAvailable回调,此时子类SomeInheritingObject的onAvailable(函数类型的属性)还未完成初始化——子类的属性赋值操作要等父类init执行完才会进行,这时onAvailable的值还是默认的null,调用onAvailable()自然会抛出NPE。
而你改用抽象函数能解决问题,是因为Kotlin中抽象函数的重写实现是在类加载阶段就确定的,函数本身不会是null;即使回调在父类init时触发,调用的是子类已存在的函数实现(不会出现属性那样的未赋值情况)。
代码层面的具体拆解
当创建SomeInheritingObject实例时:
- 首先调用父类
SomeSuperClass的构造函数,执行父类init块,注册callback到SomeManager - 若
SomeManager立即触发onAvailable回调,会调用父类中callback的onAvailable方法,进而访问子类重写的onAvailable属性 - 此时子类的
onAvailable、_state等所有属性都还未完成赋值,onAvailable为null,调用null的函数类型就会抛出NPE
可行的解决方案
除了你当前使用的抽象函数方案,还有几种常见处理方式:
- 延迟回调注册:父类不直接在
init里注册回调,而是提供一个start()方法,让子类在初始化完成后主动调用该方法注册回调,确保回调触发时子类属性已全部初始化 - 调整逻辑依赖:将回调中需要访问的子类状态逻辑提前到父类可控的初始化阶段,避免跨层级的初始化依赖
- 改用
lazy委托属性:但需确保回调触发时属性已被初始化,否则仍会出现异常
内容的提问来源于stack exchange,提问作者Linus Lindgren
相关产品推荐
相关产品推荐

