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

Groovy中如何仅重写父类的构造方法?

Groovy中如何仅重写父类的构造方法?

嘿,我来给你把这个问题掰扯明白!你遇到的报错和IntelliJ的提示,本质上都是因为继承关系里构造器的调用规则在起作用,咱们一步步拆解:

为什么会报错?

首先要记住一个关键规则:在Groovy(其实底层和Java一致)中,子类的构造器必须先调用父类的某个构造器——要么是你显式写代码调用,要么是编译器自动帮你调用父类的无参构造器。

你写的Foo类只定义了一个带两个int参数的构造器,这时候Java/Groovy会自动移除默认的无参构造器(就是那种不带任何参数的Foo(){})。而你的Bar构造器里没有显式写super(a, b)来调用父类的带参构造器,编译器就会默认帮你加一句super()——但这时候Foo根本没有无参构造器,所以就抛出了NoSuchMethodError,IntelliJ提前提示你“找不到默认构造器”也是这个原因。

你加无参构造器后为什么能运行?

当你给Foo加上Foo(){}之后,编译器自动插入的super()就有对应的构造器可以调用了,所以不会报错。但这里要注意:这时候父类的a和b是用默认值初始化的,然后你在Bar里给this.a和this.b赋值,其实是覆盖了父类的属性值,但父类原来的构造器逻辑(比如println("I'm a Foo!"))并没有执行——这可能不是你真正想要的“重写构造器”的效果。

正确的做法:显式调用父类构造器

如果你想保留父类构造器的部分逻辑,同时自定义子类的构造行为,应该显式调用父类的带参构造器,比如:

class Foo {
    def a
    def b

    Foo(int a, int b) {
        this.a = a
        this.b = b
        println("I'm a Foo!")
    }
}

class Bar extends Foo {
    Bar(int a, int b) {
        super(a, b) // 显式调用父类的带参构造器,先完成父类的初始化
        this.a = 2*a // 再自定义子类的属性赋值
        this.b = 2*b
        println("I'm a Bar!")
    }
}

def f = new Foo(1, 2)
def b = new Bar(1, 2)

这样运行的话,输出会是:

I'm a Foo!
I'm a Foo!
I'm a Bar!

因为先调用了父类的构造器执行它的逻辑,再执行子类自己的逻辑。

如果你完全不想执行父类构造器的逻辑,那其实不能直接“重写”构造器(构造器不能被重写,只能被重载或调用),这时候你可以在父类加无参构造器,然后子类构造器里只写自己的逻辑——但要清楚这时候父类的初始化逻辑不会被执行。

总结一下核心点

  • 子类构造器必须调用父类的某个构造器,显式用super(...)或者隐式调用无参super()
  • 父类如果定义了自定义构造器,默认无参构造器会被移除,需要手动添加才会存在
  • 想要自定义子类构造逻辑同时正确继承父类,优先选择显式调用父类对应的构造器

备注:内容来源于stack exchange,提问作者Chris Curvey

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.23 15:28:14