什么是构造函数
构造函数是用于创建类实例的特殊函数,通常用来初始化属性,除默认构造函数外,所有构造函数名称与类名一致。
Dart 构造函数分类:
- 生成构造函数(Generative)
- 默认构造函数(Default)
- 命名构造函数(Named)
- 常量构造函数(Const)
- 重定向构造函数(Redirecting)
- 工厂构造函数(Factory)
- 重定向工厂构造函数
- 简洁构造语法(Dart 3.13+)
- 主构造函数(Primary Constructors,极简字段 + 构造)
1. 生成构造函数 Generative Constructor
最基础构造,创建实例并初始化成员变量,支持初始化形式参数 this.变量 简化赋值。
class Point {
double x;
double y;
// 生成构造函数,this.x 直接接收参数赋值成员
Point(this.x, this.y); //直接给x y赋值了
}
void main() {
final p = Point(10, 20);
print("(${p.x}, ${p.y})"); // (10, 20)
}
Code language: JavaScript (javascript)
2. 默认构造函数 Default Constructor
若类未手动定义任何构造,Dart 自动提供无参、无名称的生成构造函数。和其他类C语言一样 C++ JAVA c#等等都是如此.
class PointA {
double x = 0;
double y = 0;
// 隐式默认构造:PointA();
}
void main() {
final p = PointA(); // 自动调用默认构造
print("(${p.x}, ${p.y})"); // (0.0, 0.0)
}
Code language: PHP (php)
注意:只要手动写了任意构造,默认构造就会消失。
3. 命名构造函数 Named Constructor
作用:一个类定义多个构造、语义清晰;格式 类名.构造名()
const double xOrigin = 0;
const double yOrigin = 0;
class Point {
final double x;
final double y;
// 主生成构造
Point(this.x, this.y);
// 命名构造:原点
Point.origin() : x = xOrigin, y = yOrigin;
}
void main() {
final p1 = Point(5, 6);
final p2 = Point.origin(); //调用命名构造函数
print(p1.x); //5
print("原点:(${p2.x}, ${p2.y})"); // (0,0)
}
Code language: PHP (php)
关键规则
- 子类不会继承父类命名构造,子类需要同名命名构造必须手动实现;
- 命名构造支持初始化列表赋值 final 变量。
4. 常量构造函数 Const Constructor
用于创建编译期常量对象,要求:
- 所有成员变量标记
final - 构造函数加
const调用时用const可复用常量缓存,不写 const 会创建普通实例。
class ImmutablePoint {
static const ImmutablePoint origin = ImmutablePoint(0, 0); //静态的属于类的,所有类共用一个
final double x, y;
// 常量构造 可以为final的x和y初始化
const ImmutablePoint(this.x, this.y);
}
void main() {
// 编译期常量,复用同一个对象
const p1 = ImmutablePoint(1, 2);
const p2 = ImmutablePoint(1, 2); //传入的值需要一样,都是1 2 如果不应用 则会不同一个对象
print(p1 == p2); // true
// 普通实例,新对象
final p3 = ImmutablePoint(1, 2);
print(p1 == p3); // false
}Code language: PHP (php)
5. 重定向构造函数 Redirecting Constructor
构造函数内部转发到同类另一个构造,使用 : this(参数),函数体必须为空。
class Point {
double x, y;
// 主构造
Point(this.x, this.y);
// 重定向构造:只传x,y固定0,转发主构造
Point.alongX(double x) : this(x, 0); //调用命名构造函数后再把x传给主够在函数,同时y的值赋0
}
void main() {
final p = Point.alongX(9);
print("x=${p.x}, y=${p.y}"); // x=9, y=0
}
Code language: JavaScript (javascript)
6. 工厂构造函数 Factory Constructor
关键字 factory,适用场景:
- 不总是新建对象(缓存复用、返回子类实例)
- 构造前复杂逻辑(解析 JSON、参数校验) 限制:不能访问
this
缓存单例 Logger
class Logger {
final String name;
bool mute = false;
// 私有缓存库内可见
static final Map<String, Logger> _cache = {};
// 工厂构造:优先取缓存
factory Logger(String name) {
return _cache.putIfAbsent(name, () => Logger._internal(name));
}
// 工厂构造:从json解析创建
factory Logger.fromJson(Map<String, dynamic> json) {
return Logger(json["name"].toString());
}
// 私有内部生成构造
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
void main() {
final log1 = Logger("UI");
final log2 = Logger("UI");
print(log1 == log2); // true 同一缓存对象
final jsonLog = Logger.fromJson({"name": "Net"});
jsonLog.log("request success");
}
Code language: JavaScript (javascript)
7. 重定向工厂构造函数 Redirecting Factory
格式 factory 名称() = 其他类构造;,适合抽象类代理实例创建,省去重复参数定义。
abstract class Listenable {}
class _MergingListenable implements Listenable {
List<_MergingListenable> list;
_MergingListenable(this.list);
}
// 重定向工厂,调用内部私有类构造
factory Listenable.merge(List<Listenable> list) = _MergingListenable;
Code language: PHP (php)
8. 构造函数撕裂 Constructor Tear-offs
直接把构造函数当作函数参数传递,省略 (),替代 lambda 匿名函数,性能更好。
推荐写法
void main() {
final charCodes = [65, 66, 67];
// 命名构造 String.fromCharCode
final strs = charCodes.map(String.fromCharCode);
print(strs); // (A, B, C)
// 无名称构造撕裂 .new
final buffers = charCodes.map(StringBuffer.new);
}
Code language: PHP (php)
不推荐冗余 lambda
// 多余包裹,不推荐
charCodes.map((code) => String.fromCharCode(code));
Code language: JavaScript (javascript)
9. Dart 3.13+ 简洁构造语法 Concise Constructor
类内可省略类名,直接使用 new / factory 定义构造,无需类名.xxx:
| 传统写法 | 简写 |
|---|---|
Point(this.x,this.y) | new(this.x,this.y) |
Point.origin():x=0,y=0 | new origin():x=0,y=0 |
factory Point.clone() | factory clone() |
class Point {
double x, y;
// 简写无参生成构造
new(this.x, this.y);
// 简写命名生成构造
new origin() : x = 0, y = 0;
// 简写工厂构造
factory clone(Point other) => new(other.x, other.y);
}
void main() {
final p = new(3, 4);
final origin = new origin();
final copy = p.clone(p);
}
Code language: PHP (php)
10. 实例变量初始化三种方式
1:声明时直接赋值
class PointA {
double x = 1.0;
double y = 2.0;
}
Code language: JavaScript (javascript)
2:初始化形式参数
this.变量
支持可选参数、命名参数、nullable 变量
class PointB {
final double x;
final double y;
// 位置可选参数
PointB.opt([this.x = 0, this.y = 0]);
// 命名参数带默认值
PointB.named({this.x = 5, this.y = 5});
}
Code language: JavaScript (javascript)
3:初始化列表 Initializer List
冒号 : 后赋值,执行时机早于构造函数体,不能访问 this,支持 assert 参数校验
class Point {
final double x;
final double y;
Point.fromJson(Map<String, double> json)
: x = json["x"]!,
y = json["y"]! {
print("构造体执行,x=$x");
}
// 带断言校验
Point.withAssert(this.x, this.y) : assert(x >= 0);
}
Code language: JavaScript (javascript)
11. 私有字段直接初始化参数(Dart3.12+)
带下划线私有变量,构造参数写 this._字段,外部调用直接使用无下划线公开名。
class Point {
final double _x;
final double _y;
// 内部 _x,外部调用写 x:10
Point({required this._x, this._y = 0});
}
void main() {
final p = Point(x: 10); // 不传 _x,直接 x
print(p._x); // 10
}
Code language: PHP (php)
初始化列表中使用私有变量原名:
class Point {
final double _x;
Point({required this._x}) : assert(_x > 0);
}
Code language: JavaScript (javascript)
12. 父类构造与构造继承规则
- 子类不继承任何父类构造;
- 构造执行顺序:初始化列表 → 父类构造 → 子类构造体;
- 父类若无无参默认构造,子类必须手动
super()指定父类构造。
基础 super 调用示例
和java类似,使用super来表示基类,C#中使用base。
class Person {
final String name;
Person(this.name);
Person.fromMap(Map map) : name = map["name"];
}
class Employee extends Person {
int id;
// 调用父类命名构造
Employee(Map data) : super.fromMap(data), id = data["id"];
}
Code language: JavaScript (javascript)
注意:super 参数表达式不能使用
this。
Super 参数(Dart2.17+,简化父类传参)
用 super.变量 直接转发参数给父类,无需手动 super(x,y)
class Vector2d {
final double x, y;
Vector2d(this.x, this.y);
}
class Vector3d extends Vector2d {
final double z;
// super.x super.y 自动转发父类构造
Vector3d(super.x, super.y, this.z);
}
// 父类命名构造 + super 命名参数
class Vector3dYZ extends Vector2d {
final double z;
Vector3dYZ({required super.y, required this.z}) : super.named(x: 0);
}
Code language: JavaScript (javascript)
Previous: 类 class