Kotlin继承场景中子类成员变量值被父类设置后重置为默认值的问题咨询
Kotlin继承场景中子类成员变量值被父类设置后重置为默认值的问题咨询
嗨,我来帮你梳理这个问题的根源和解决办法~
问题到底出在哪?
你遇到的核心问题是Kotlin继承体系的初始化顺序导致的变量值被覆盖,咱们一步步拆解创建TextElement实例时的执行流程:
- 调用
TextElement的次构造函数时,首先会执行super(binaryReader)调用父类Element的构造函数 - 父类构造函数内部调用
decode方法,此时会把TextElement的textGravity设置为Element.HorizontalGravity.MIDDLE - 等父类构造函数完全执行完后,回到子类,才会执行子类成员属性的初始化语句:
var textGravity = Element.HorizontalGravity.DEFAULT——这一步直接把父类刚设置的值给覆盖了,所以你看到值又变回默认了!
简单说就是:父类构造函数的执行早于子类成员属性的初始化器,父类辛辛苦苦设的值,被子类的默认初始化给冲掉了。
针对你的场景的解决方案
既然你说现有结构不能大改,那推荐这两种最适配的方案:
方案1:用lateinit var避免默认初始化
把textGravity声明为延迟初始化变量,这样就不会有默认值覆盖的问题,同时确保父类的赋值能保留下来:
class TextElement : Element { lateinit var textGravity: Element.HorizontalGravity constructor(binaryReader: BinaryReader) : super(binaryReader) { decode(binaryReader) // 保险起见:如果父类decode没赋值(虽然你的场景里一定会赋值),就设默认值 if (!::textGravity.isInitialized) { textGravity = Element.HorizontalGravity.DEFAULT } } }
这种方式不需要修改父类代码,完全在子类调整,适配你不能改原有结构的需求。
方案2:用可空类型配合初始化块兜底
如果不想用lateinit,也可以把变量设为可空类型,在初始化块里判断是否已被父类赋值,没赋值再设默认:
class TextElement : Element { var textGravity: Element.HorizontalGravity? = null constructor(binaryReader: BinaryReader) : super(binaryReader) { decode(binaryReader) } init { // 只有父类没赋值的时候才用默认值 textGravity = textGravity ?: Element.HorizontalGravity.DEFAULT } }
这种方式需要处理空安全,但逻辑也很清晰,同样不需要修改父类代码。
小提醒
虽然你现在不能改结构,但还是得说一句:父类构造函数里直接操作子类成员是很危险的写法,属于反模式——因为父类执行时子类还没完全初始化,很容易出各种奇怪的问题。等后续有机会重构的话,建议把这类逻辑改成父类定义抽象方法,子类实现,或者用回调的方式,会更安全。
备注:内容来源于stack exchange,提问作者NullPointerException
相关产品推荐
相关产品推荐

