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

Kotlin中构造函数调用抽象方法初始化变量失效问题咨询

解决Kotlin父类init块调用抽象方法导致子类变量赋值被覆盖的问题

这个问题的核心是Kotlin与Java的类初始化顺序差异。在Kotlin中,创建子类实例的执行顺序是:

  1. 先执行父类的所有init块和构造逻辑
  2. 再初始化子类的成员变量(也就是你写的=404这类赋值操作)
  3. 最后执行子类的init块

所以当父类init块调用getUniforms()给子类的loc_projectionMatrix等变量赋值为0、1、2时,这些值会被后续子类成员变量的=404覆盖,导致最终dump()输出还是默认值。而Java中如果你的代码没有显式给成员变量赋值默认值(或赋值逻辑在构造函数内),就不会触发这个覆盖问题。

下面提供两种无需手动调用初始化函数的可行解决方案:

方案1:使用Delegates.notNull()委托(推荐)

Kotlin的kotlin.properties.Delegates.notNull()允许你声明非空的基本类型变量,且不需要设置默认值(从根源避免覆盖)。它要求变量必须在第一次使用前完成赋值,刚好匹配你的场景——父类init块调用getUniforms()完成赋值。

修改BoilerplateShader的变量声明:

import kotlin.properties.Delegates

abstract class BoilerplateShader() : Shader(){
    var loc_projectionMatrix: Int by Delegates.notNull()
    var loc_transformationMatrix: Int by Delegates.notNull()
    var loc_viewMatrix: Int by Delegates.notNull()

    override fun getUniforms(){
        loc_projectionMatrix = 0
        loc_transformationMatrix = 1
        loc_viewMatrix = 2
        println(loc_projectionMatrix.toString() + ", " + loc_transformationMatrix + ", " + loc_viewMatrix)
    }

    // 其他代码保持不变
}

这样子类变量不会有默认值赋值步骤,父类init块中getUniforms()的赋值会被保留,执行dump()时就能得到正确的0、1、2。

方案2:调整初始化顺序,将父类逻辑移到子类init块执行

把父类init块的逻辑提取为一个受保护的方法,然后在子类的init块中调用它。由于子类的init块是在子类成员变量初始化之后执行的,此时赋值会覆盖默认的404:

首先修改父类Shader:

abstract class Shader {
    // 将原init块逻辑迁移至此
    protected open fun initializeShader() {
        bindAttribs()
        getUniforms()
    }

    abstract fun getUniforms()
    abstract fun bindAttribs()
}

然后修改子类BoilerplateShader:

abstract class BoilerplateShader() : Shader(){
    var loc_projectionMatrix: Int = 404
    var loc_transformationMatrix: Int = 404
    var loc_viewMatrix: Int = 404

    init {
        initializeShader() // 子类init块调用,此时成员变量已完成默认初始化,赋值会覆盖404
    }

    override fun getUniforms(){
        loc_projectionMatrix = 0
        loc_transformationMatrix = 1
        loc_viewMatrix = 2
        println(loc_projectionMatrix.toString() + ", " + loc_transformationMatrix + ", " + loc_viewMatrix)
    }

    // 其他代码保持不变
}

这种方案不需要修改变量类型,仅调整了初始化逻辑的执行时机,同样能解决问题。

额外提醒

虽然Java中类似代码可能表现正常,但在父类构造中调用子类抽象方法本质上是一种不安全的实践(无论Java还是Kotlin),因为此时子类可能尚未完全初始化。如果条件允许,建议重构设计避免这种写法;若必须保留现有结构,上述两种方案均可满足你的需求。

内容的提问来源于stack exchange,提问作者Zoe - Save the data dump

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:52:23