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

抽象类主构造器含默认值不可变变量,子类如何实现双构造器赋值?

解决Scala抽象类子类不可变变量的构造器问题

这个问题的核心在于不可变变量(val)一旦初始化就无法修改,所以你不能先让父类用默认值初始化someVal,再试图在子类的辅助构造器里改变它——这完全违背了val的设计初衷。下面是正确的实现方式:

第一步:定义抽象类

首先你的抽象类主构造器的定义是没问题的,带默认值的不可变变量:

abstract class BaseClass(val someVal: String = "defaultVal")

第二步:正确实现子类

要同时支持SubClass()和SubClass("anotherVal")两种实例化方式,你需要让子类的主构造器直接接收参数(并设置默认值),然后把这个参数传递给父类的主构造器。这样父类的someVal在初始化时就拿到了正确的值,完全符合不可变的要求:

class SubClass(someVal: String = "defaultVal") extends BaseClass(someVal)

为什么这样可行?

  • 当你调用SubClass()时,子类主构造器使用默认值"defaultVal",并把它传给父类的主构造器,父类的someVal就初始化为默认值。
  • 当你调用SubClass("anotherVal")时,子类把自定义值传给父类,父类的someVal直接初始化为这个自定义值。
  • 父类的someVal是不可变的,子类继承了这个属性,全程没有任何修改操作,完全符合要求。

可选:显式override父类的val

如果你想让子类自己也显式拥有这个someVal属性(其实父类已经提供了,子类可以直接访问),可以加上override关键字:

class SubClass(override val someVal: String = "defaultVal") extends BaseClass(someVal)

效果和上面的实现完全一致,只是更明确地表明你重写了父类的val属性。

测试代码

验证一下两种实例化方式的效果:

val sc = SubClass()
println(sc.someVal) // 输出: defaultVal

val sc2 = SubClass("anotherVal")
println(sc2.someVal) // 输出: anotherVal

为什么之前的实现会报错?

如果你之前尝试用子类的辅助构造器来实现,比如:

class SubClass extends BaseClass {
  def this(someVal: String) = {
    this() // 先调用主构造器,父类已经用默认值初始化了someVal
    // 这里试图修改someVal?不可能,因为它是val
  }
}

这种写法必然报错,因为父类的someVal在调用this()时已经被初始化为默认值,而val是不可变的,你没有任何办法再修改它。这也是为什么必须在父类初始化时就传递正确的值。

内容的提问来源于stack exchange,提问作者codependent

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:44:03