在前面的系列文章(文章末尾会有传送门哦~~)都是些比较简单的基础概念,之后就要开始介绍一些注重理解和手动实践的Dart知识了。这篇的内容主要是Dart中的类的构造方法。
Dart是一种面向对象的语言,具有类和基于mixin的继承。每个对象都是一个类的实例,所有的类都是Object的子类。
核心内容如下
- 普通构造方法
- 常量构造方法
- 初始化列表
- 工厂构造方法
类的成员
和java语言类似,使用点号(.)引用实例变量或方法
var p = Point(2, 2);
// Set the value of the instance variable y.
p.y = 3;
但它还可以这么写
// If p is non-null, set its y value to 4.
p?.y = 4;
这是为避免最左操作数为空时出现异常,使用 ?.代替 .
构造方法
普通构造方法
如果不声明构造方法,则为您提供默认构造方法。默认构造方法没有参数,并在超类中调用无参数构造函数。
如果有多个构造方法,构造方法的写法和Java不太一样。即使构造方法的参数不同,这些构造方法的命名也不能重复
那如果有多个构造方法,我们可以通过ClassName.identifier作为它的构造方法,比如下面的Point.fromJson
class Point{
var x;
var y;
Point(var x,var y){
this.x=x;
this.y=y;
}
Point.fromJson(Map<String, int> map) {
x=map['x'];
y=map['y'];
}
}
调用构造方法
var p1 = new Point(2, 2);
var p2 = new Point.fromJson({'x': 1, 'y': 2});
当然我们这里的new关键字是可以省略的
在Dart2中new关键字为可选关键字
常量构造方法
class ImmutablePoint {
final num x, y;
const ImmutablePoint(this.x,this.y);//常量构造方法
}
常量构造方法需要添加关键字const,并且是没有身体的,直接在末尾加;即可
var a = const ImmutablePoint(1, 1);
var b = const ImmutablePoint(1, 1);
assert(identical(a, b));
print(a==b); //true
print(b); //Instance of 'ImmutablePoint'
构造两个相同的编译时常量会生成一个单一的、规范的实例
在常量上下文中,可以在构造函数或文字之前省略const。例如,它创建了一个const的 map集合
//这里用来很多const
const pointAndLine = const {
'point': const [const ImmutablePoint(0, 0)],
'line': const [const ImmutablePoint(1, 10), const ImmutablePoint(-2, 11)],
};
//可以省略除第一个外的其他const
const pointAndLine = {
'point': [ImmutablePoint(0, 0)],
'line': [ImmutablePoint(1, 10), ImmutablePoint(-2, 11)],
};
初始化列表
上面的Point类我们可以这么写
Point.fromJson(Map<String, int> map):
x=map['x'],
y=map['y']{
print('In Point.fromJson(): ($x, $y)');
}
调用超类构造方法之外,还可以在构造函数主体运行之前初始化实例变量,初始值设定项用逗号分开。
可以通过在初始化列表中使用assert来验证输入
Point.withAssert(this.x, this.y) : assert(x >= 0) {
print('In Point.withAssert(): ($x, $y)');
}
这样写有什么好处呢?
初始化列表在设置final字段时很方便
我们在构造方法的body里设置final变量是不能编译通过,但通过这种方式就是ok的
import 'dart:math';
class Point {
final num x;
final num y;
final num distanceFromOrigin;
Point(x, y)
: x = x,
y = y,
distanceFromOrigin = sqrt(x * x + y * y);
}
main() {
var p = new Point(2, 3);
print(p.distanceFromOrigin);
}
///运行结果
3.605551275463989
工厂构造方法
工厂构造方法可以从缓存返回实例,也可以返回子类型的实例。
在实现构造方法时使用factory关键字,工厂构造方法并不总是创建类的新实例。
class Logger {
final String name;
bool mute = false;
//用于缓存已经实例化的对象
static final Map<String, Logger> _cache =
<String, Logger>{};
factory Logger(String name) {
if (_cache.containsKey(name)) { //如果map缓存里存在直接返回实例
return _cache[name];
} else { //如果map缓存里不存在,则返回新的实例
final logger = Logger._test(String name):this.name=name;;
_cache[name] = logger;
return logger;
}
}
//???
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
上面代码还是比较好理解的,不知道在我标记问号的那句代码你有没有懵逼?反正我看的时候是感觉有点奇怪的。
其实仔细一研究,它其实等价于这样的写法
Logger._internal(String name):this.name=name;
Dart相关系列的传送门