Dart初始化列表中父类构造函数为何最后调用?
为什么Dart初始化列表中父类构造函数会被最后调用?
先看修正后的代码示例:
class Foo { String name; Foo.create(Map map) : name = map["name"]; } class Bar extends Foo { int value; Bar.create(Map map) : value = map["value"], super.create(map); }
Dart这样设计核心是为了让子类能在父类构造执行前完成自身成员变量的初始化,甚至可以基于子类的状态为父类构造提供参数,和Java的父类优先逻辑完全相反,具体原因如下:
确保子类状态完整后再执行父类逻辑
Dart要求初始化列表中,子类的实例变量赋值、自定义初始化表达式必须在super调用之前执行。这样可以保证子类自己的成员变量都已经有了确定的值,再进入父类构造的执行流程,避免了Java中父类构造执行时,子类成员还未初始化的潜在问题(比如父类构造调用子类重写方法时拿到默认值)。支持基于子类状态传递参数给父类
你可以在初始化列表中先处理子类的变量,再把处理后的结果传给父类构造。比如:class Bar extends Foo { int value; Bar.create(Map map) : value = int.parse(map["value"]), super.create({"name": "Bar_${map["name"]}"}); }这种场景在Java中很难直接实现,因为Java必须先调用父类构造,此时子类变量还未初始化,无法用来生成父类构造的参数。
语法规则的强制要求
Dart的初始化列表执行顺序是固定的:- 子类实例变量的初始化赋值
- 初始化列表中的其他自定义表达式
- 父类构造函数调用
所以super必须放在初始化列表的最后一位,这是语法层面的强制规定,也是上述设计目标的体现。
对比Java的逻辑:Java会先执行父类构造,再初始化子类成员变量,最后执行子类构造函数体。这种顺序虽然保证了父类先完成初始化,但也带来了子类状态未就绪时被父类逻辑访问的风险。
内容的提问来源于stack exchange,提问作者eastwater
相关产品推荐
相关产品推荐

