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

Kotlin继承场景中子类成员变量值被父类设置后重置为默认值的问题咨询

Kotlin继承场景中子类成员变量值被父类设置后重置为默认值的问题咨询

嗨,我来帮你梳理这个问题的根源和解决办法~

问题到底出在哪?

你遇到的核心问题是Kotlin继承体系的初始化顺序导致的变量值被覆盖,咱们一步步拆解创建TextElement实例时的执行流程:

  1. 调用TextElement的次构造函数时,首先会执行super(binaryReader)调用父类Element的构造函数
  2. 父类构造函数内部调用decode方法,此时会把TextElement的textGravity设置为Element.HorizontalGravity.MIDDLE
  3. 等父类构造函数完全执行完后,回到子类,才会执行子类成员属性的初始化语句: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 09:55:30