Dart中的构造函数
Posted 阳光明媚123
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dart中的构造函数相关的知识,希望对你有一定的参考价值。
Dart中的构造函数有4种,分别是:
- ClassName(...) //普通构造函数
- Classname.identifier(...) //命名构造函数
- const ClassName(...) //常量构造函数
- factroy ClassName(...) //工厂构造函数
普通构造函数
普通构造函数可以分为无参构造函数和有参构造函数。
如果不声明构造函数,则dart会提供一个默认的无参构造函数。当然,也可以自己定义有参构造函数,如果自己写了构造函数,那么默认构造函数就不存在了。
我们可以这么来定义一个有参构造函数
class People
int? age;
String? name;
People(int age, String name)
this.age = age;
this.name = name;
这种赋值方式如果变量很多的话写起来比较麻烦,所以dart提供了语法糖来简化,直接在参数列表上这么写:
class People
int? age;
String? name;
People(this.age, this.name);
注意:
- Dart 构造函数不允许重载,即不允许有相同名称的构造函数,否则编译器会报错
如果想设置不同的参数可通过可选参数列表来设置:
class People
int? age;
String? name;
People(this.age, this.name);
这种写法涵盖了这么几种形式:
People();
People(this.age);
People(this.name);
People(int age, String name);
- 当子类继承父类时,初始化子类构造函数会优先初始化父类构造函数,继承时需要使用 super调用父类构造函数,若父类为无参构造函数时可以省略。
class Child extends People
Child(int age, String name): super(age: age, name: name);
// Child(int age, String name); 若父类为无参构造函数时则可以省略super调用
命名构造函数
格式:类名.构造函数名
class People
int? age;
String? name;
People.fromMap(Map map)
this.age = map["age"];
this.name = map["name"];
使用命名构造函数可为一个类实现多个构造函数,但是同样是不能重载。
如果一个里只有命名构造函数,那么子类需要显示调用父类的命名构造函数。
class B extends People
B(Map map) : super.fromJson(map);
否则会报错
初始化列表
除了调用父类的构造函数,你还可以在执行构造函数体及调用父类构造函数之前初始化实例变量,使用逗号分隔每个初始化变量。
class Employee extends People
int? no;
String? job;
String? address;
int? age1;
Employee(this.job, this.address, int? age)
: this.no = 123456,
age1 = age ?? 25,
super(age: age);
调用的顺序如下:
- 初始化列表
- 父类的构造函数
- 子类的构造函数
参数列表对于初始化那些final修饰的成员变量很有用,因为在方法体中,不能给final修饰的成员变量赋值,因为在执行方法体的时候,final修饰的成员变量已经不能变了。
注意:
- 传递给父类构造函数的参数及初始化表达式的右边不能使用 this 关键字和访问实例成员变量,因为在参数传递的这一步骤,子类构造函数尚未执行,子类的实例对象也就还未初始化,因此所有的实例成员都不能被访问。
- 同一实例成员在参数列表和初始化列表中不能同时存在,
构造函数传递(重定向构造函数)
定义构造函数的时候,除了可以定义一个普通构造函数之外,还可以定义若干个命名构造函数,这些构造函数之间,有时候会有一些相同的逻辑,如果分别写在各个构造函数中,会显得有些多余,所以构造函数可以传递。传递构造函数是没有方法体的,可以在初始化列表中,调用另一个构造函数。
class Point
final num x;
final num y;
final num area;
Point(x, y)
: this.x = x,
this.y = y,
this.area = x * x + y * y;
Point.alongXAxis(num x) : this(x, 0);
如果添加方法体,编译器会报错。
常量构造函数
如果生成类的对象是不会变的,可以定义常量构造函数(如果你的类,创建的对象永远不会改变,你可以在编译期就创建这个常量实例,并且定义一个常量构造函数,并且确保所有的成员变量都是final的。)。
class Point
final num x;
final num y;
final num area;
const Point(x, y)
: this.x = x,
this.y = y,
this.area = x * x + y * y;
在使用时需注意:
- 常量构造函数必须用 const 关键词修饰;比如我们定义一个常量,给该常量赋的值必须也是常量。(使用const赋值声明,后面的const可省略)。
- 所有实例变量必须是 final 类型的。
- 常量构造函数不允许有函数体。
- 实例化时需要加 const, 否则实例化的对象仍然可以修改变量值。
工厂构造函数
有时候可能有一种需求,并不需要每次都创建新的类实例,而是每一种情况,只需要一个实例,这时候工厂构造函数就派上用场了。
工厂构造函数使用关键字factory来定义,factory可以放在类名函数之前,也可以放在命名函数之前。
使用场景:
- 避免创建过多的重复实例,如果已创建该实例,则从缓存中拿出来。
class Logger final String name; bool mute = false; // _cache 变量是库私有的,因为在其名字前面有下划线。 static final Map<String, Logger> _cache = <String, Logger>; factory Logger(String name) return _cache.putIfAbsent( name, () => Logger._internal(name)); //工厂构造函数里可以调用其他构造函数。 factory Logger.fromJson(Map<String, Object> json) return Logger(json['name'].toString()); Logger._internal(this.name); void log(String msg) if (!mute) print(msg);
- 实现简单工厂模式,在java中抽象类是不能直接被实例化的,但是在dart中,使用工厂构造函数可以让抽象类被实例化。
abstract class Animal String? name; void getNoise(); factory Animal(String type, String name) switch (type) case "cat": return new Cat(name); case "dog": return new Dog(name); default: throw "The '$type' is not an animal"; class Cat implements Animal String? name; Cat(this.name); @override void getNoise() print("$this.name: 喵~"); class Dog implements Animal String? name; Dog(this.name); @override void getNoise() print("$this.name: 旺~"); void main() var cat = new Animal("cat", "花花"); var dog = new Animal("dog", "小黑"); cat.getNoise(); // 花花: 喵~ dog.getNoise(); // 小黑: 旺~
- 单例模式,可用于工具类。
class Singleton static final Singleton _singleton = Singleton._internal(); factory Singleton() return _singleton; Singleton._internal(); void main() var s1 = Singleton(); var s2 = Singleton(); print(identical(s1, s2)); // true
注意:
- 工厂构造函数不能和其他构造函数一样,使用this关键字来调用class的属性和方法。工厂构造函数只能使用类中static类型的属性和方法。
- 在其他类型的构造函数方法体里是不能有返回值,也就是不能出现return关键字,但是工厂函数是必须要有的,而且不能返回null。
Dart:Dart 如何匹配类的构造函数中的命名参数?
【中文标题】Dart:Dart 如何匹配类的构造函数中的命名参数?【英文标题】:Dart: How does Dart match the named parameters in a Constructor of a Class? 【发布时间】:2019-08-28 03:13:23 【问题描述】:Dart 如何匹配类的构造函数中的命名参数?
示例(有效):
Class MyWidget
final String a;
final String b;
MyWidget (
@required this.a,
@required this.b
)
@override // Yes, it's Flutter
Widget build(BuildContext context)
return ....
/// Calling MyWidget
return MyWidget(
a: x,
b: y
)
这按预期工作。 但是在这个设置中,我不得不将 MyWidget 中的变量命名为与命名参数相同,因为调用中的“a”与 MyWidget 中的“this.a”相同。
我想要的是这样的:
Class MyWidget
final String aaa;
final String bbb;
MyWidget (
@required a // And assign that value to this.aaa,
@required b // And assign that value to this.bbb
)
如何将传递的命名参数“a”的值分配给局部变量“aaa”?
【问题讨论】:
【参考方案1】:您必须权衡this.xxx
语法的简单性,如下所示:
class MyWidget
final String aaa;
final String bbb;
MyWidget(a, b)
: aaa = a,
bbb = b;
【讨论】:
感谢 Richard,我还在 Dartlang 手册中找到了它。它被称为“initializer list”以上是关于Dart中的构造函数的主要内容,如果未能解决你的问题,请参考以下文章