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

Dart子类两种构造函数差异解析:为何一个可行一个报错?

Dart构造函数初始化列表中super调用的差异解析

问题背景

下面是继承自类A的类B代码:

class A {
  A(int value){
    print(value);
  }
}

class B extends A{
  int x;

  B.one(this.x) : super(x);

  B.two(int x) : this.x = x, super(this.x); 
}

类B包含B.one()和B.two()两个构造函数,仅B.one()可正常工作,B.two()调用super(this.x)会报错。原本认为B.one()是B.two()的简写,却疑惑两者传参给父类的方式存在差异。

尝试将B.two()修改为以下代码后可正常运行:

class A {
  A(int value){
    print(value);
  }
}

class B extends A{
  int x;

  B.one(this.x) : super(x);

  B.two(int x) : this.x = x, super(x); 
}

修改后移除super中的this关键字即可正常运行,但不解为何B.one()可直接传递字段x给父类,而B.two()却需使用构造函数参数x。

原因解析

核心在于Dart构造函数初始化列表的执行顺序:

  • 第一步:先确定构造函数所有参数的具体值,这些参数此时处于可用状态。
  • 第二步:执行父类构造函数(即super()调用),这一步会在子类的实例字段初始化之前完成。
  • 第三步:才会执行子类初始化列表里的字段赋值操作(比如this.x = x)。

对两个构造函数分别拆解:

  • B.one(this.x) : super(x)
    这里的this.x是Dart语法糖,本质是构造函数接收参数x,并直接将该参数赋值给实例字段x。而super(x)中的x指代的是构造函数的参数x——这个参数在第一步就已确定值,因此可以直接传递给父类构造,不会有问题。

  • 原始错误的B.two(int x) : this.x = x, super(this.x)
    super(this.x)里的this.x是子类的实例字段,但按照执行顺序,父类构造会先执行,此时this.x = x还未执行,实例字段x仍为默认的null,将null传给需要int类型的父类构造自然会触发错误。

  • 修改后的B.two(int x) : this.x = x, super(x)
    super(x)使用的是构造函数的参数x,该参数在第一步已确定值,无论后续this.x = x何时执行,都能正常将参数值传递给父类构造,因此可以正常运行。

简单来说:B.one()里的super(x)用的是构造函数参数,而非已初始化的实例字段;B.two()若写super(this.x),则是在实例字段初始化前引用它,必然出错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 14:33:11