最常见的构造函数形式,即生成构造函数,创建一个类的新实例:
1class Point {
2 num x, y; //Dart中int和double是num的子类
3
4 //this引用当前类对象
5 Point(num x, num y) {
6 this.x = x;
7 this.y = y;
8 }
9}
使用语法糖的时候可以这样定义:
1class Point {
2 num x, y;
3
4 //用于设置x和y的语法糖
5 //在构造函数体运行之前
6 Point(this.x, this.y);
7
8 @override
9 String toString() {
10 return ("x: $x, y: $y");
11 }
12}
13
14//print(new Point(100, 200)); -> 打印 x: 100, y: 200
默认构造函数
如果未声明构造函数,则会提供默认构造函数。 默认构造函数没有参数,并在调用父类无参数构造函数。
1class Parent{
2 Parent(){
3 print('In Parent\'s constructor.');
4 }
5}
6
7class Child extends Parent{
8 Child(){
9 print('In Child\'s constructor.');
10 }
11}
12
13//new Child(); -> 打印 In Parent's constructor. In Child's constructor.
构造函数不能继承
子类不能继承其父类构造函数,一个没有声明构造函数的子类只有默认(无参数,无名称)构造函数
命名构造函数
当我们需要定义一个有特别含义的构造函数的时候,可以通过构造函数.XXX来命名构造函数
1class Point{
2 num x;
3 num y;
4
5 Point(this.x, this.y);
6
7 //创建一个坐标原点类
8 Point.origin(){
9 this.x = 0;
10 this.y = 0;
11 }
12
13 //创建一个坐标为(100, 100)的类
14 Point.coordinate100(){
15 this.x = 100;
16 this.y = 100;
17 }
18 @override
19 String toString() {
20 return ("x: $x, y: $y");
21 }
22}
调用父类构造函数
默认情况下,子类中的构造函数调用父类的未命名无参数构造函数。 父类的构造函数在子类构造函数体的开头被调用。 如果还使用初始化了列表,则会在调用父类构造函数之前执行。 执行顺序如下:
- 初始化列表
- 父类的无参数构造函数
- 子类的无参数构造函数
如果父类没有未命名的无参数构造函数,则必须手动调用父类中的一个构造函数。 在子类的构造函数体之后用冒号(:)指定父类构造函数
例1:默认先调用父类的无参数构造函数
1class Parent{
2 Parent(){
3 print('In Parent\'s constructor.');
4 }
5}
6
7
8class Child extends Parent{
9 Child(num x, num y) {
10 print('In Child\'s constructor.');
11 }
12}
13
14//new Child(100, 100); -> 打印
15//In Parent's constructor.
16//In Child's constructor.
例2:手动调用父类其他构造函数
1class Parent{
2 num x;
3 num y;
4 Parent(this.x, this.y){
5 print('In Parent\'s constructor.');
6 }
7}
8
9class Child extends Parent{
10 Child(num x, num y) : super(x, y){
11 print('In Child\'s constructor.');
12 }
13}
14
15//new Child(100, 100); -> 打印
16//In Parent's constructor.
17//In Child's constructor.
关于初始化列表:
调用父类构造函数之前,可以在构造函数体执行之前初始化示例变量,用逗号分隔,该过程叫初始化列表。
1class Parent{
2 num x;
3 num y;
4 num sum;
5
6 Parent(num px, num py) : x = px, y = py, sum = px + py{
7 print("x: $x, y: $y, sum: $sum");
8 print('In Parent\'s constructor.');
9 }
10}
11
12class Child extends Parent{
13 Child(num x, num y) : super(x, y){
14 print('In Child\'s constructor.');
15 }
16}
17
18// new Child(100, 100); -> 打印
19//x: 100, y: 100, sum: 200
20//In Parent's constructor.
21//In Child's constructor.
重定向构造函数
有时构造函数需要重定向到同一个类中的另一个构造函数,在冒号后面用this:
1class Point {
2 num x, y;
3
4 //类的主构造函数
5 Point(this.x, this.y);
6
7 //重定向到主构造函数
8 Point.alongXAxis(num x) : this(x, 0);
9}
常量构造函数
如果你的类需要成为永远不会更改的对象,则可以使这些对象成为编译时常量。 定义const构造函数要确保所有实例变量都是final。
1class Point {
2 final num x;
3 final num y;
4 static final Point2 origin = const Point2(0, 0);
5
6 //const关键字放在构造函数名称之前,且不能有函数体
7 const Point2(this.x, this.y);
8}
没有定义final时提示:
使用函数体时提示:
工厂构造函数
在实现不用总是创建新的类对象的时候,可以使用factory关键字。 例如,工厂构造函数可能从缓存中返回实例,或者它可能返回子类型的实例:
1class Logger {
2 final String name;
3 bool mute = false;
4
5 //工厂构造函数无法访问this,所以这里要用static
6 //维护一个缓存的Map对象,
7 static final Map<String, Logger> _cache =
8 <String, Logger>{};
9
10 //调用该构造函数的时候,会从Map中取出对象
11 factory Logger(String name) {
12 if (_cache.containsKey(name)) {
13 return _cache[name];
14 } else {
15 final logger = Logger._internal(name);
16 _cache[name] = logger;
17 return logger;
18 }
19 }
20
21 Logger._internal(this.name);
22
23 void log(String msg) {
24 if (!mute) print(msg);
25 }
26}
27
28//调用
29var logger = Logger('UI');
30logger.log('Button clicked');
个人笔记记录 2021 ~ 2025