一、静态成员与实例成员
class A {
static int num1 = 1; // 静态属性
int num2 = 2; // 实例属性
static int bar() => 10; // 静态方法
int baz() => 20; // 实例方法
}
var a = new A();
print(A.num1); // 1
print(A.bar()); // 10
print(a.num2); // 2
print(a.baz()); // 20
二、构造函数
构造函数名与类名相同:
class Point {
num x;
num y;
Point(num x, num y) {
this.x = x;
this.y = y;
}
}
可以简写为:
class Point {
num x;
num y;
Point(this.x, this.y);
}
实例化:
var p1 = new Point(2, 2);
// 或者
Point p1 = new Point(2, 2);
在 Dart 中 new 关键字可以省略:
var p1 = Point(2, 2);
三、命名构造函数
使用命名构造函数可以为一个类实现多个构造函数, 或者使用命名构造函数来更清晰的表明你的意图:
class Point {
num x;
num y;
Point(this.x, this.y);
// Named constructor
Point.fromJson(Map json) {
x = json['x'];
y = json['y'];
}
}
实例化:
var p2 = new Point.fromJson({"x": 1, "y": 2});
print(p2.x); // 1
print(p2.y); // 2
四、调用超类构造函数
构造函数不能继承,所以超类的命名构造函数 也不会被继承。如果你希望 子类也有超类一样的命名构造函数, 你必须在子类中自己实现该构造函数。
默认情况下,子类的构造函数会自动调用超类的 无名无参数的默认构造函数。 超类的构造函数在子类构造函数体开始执行的位置调用。 如果提供了一个 initializer list(初始化参数列表) ,则初始化参数列表在超类构造函数执行之前执行。 下面是构造函数执行顺序:
- initializer list(初始化参数列表)
- superclass’s no-arg constructor(超类的无名构造函数)
- main class’s no-arg constructor(主类的无名构造函数)
如果超类没有无名无参数构造函数, 则你需要手工的调用超类的其他构造函数。 在构造函数参数后使用冒号 (:) 可以调用超类构造函数。
class Circle extends Point {
num r;
Circle.fromJson(Map data) : super.fromJson(data) {
r = data['r'];
}
}
实例化:
Circle c = Circle.fromJson({"x": 1, "y": 2, "r": 10});
print(c.x); // 1
print(c.y); // 2
print(c.r); // 10
五、初始化列表
在构造函数体执行之前除了可以调用超类构造函数之外,还可以 初始化实例参数。 使用逗号分隔初始化表达式。
class Circle extends Point {
num r;
Circle.fromJson(Map data) :
r = data['r'],
super.fromJson(data);
}
初始化表达式等号右边的部分不能访问 this。
初始化列表非常适合用来设置 final 变量的值:
class Point {
final num x;
final num y;
Point(x, y)
: x = x,
y = y;
Point.fromJson(Map json)
: x = json['x'],
y = json['y'];
}
class Circle extends Point {
num r;
Circle(x, y, this.r): super(x, y);
Circle.fromJson(Map data) :
r = data['r'],
super.fromJson(data);
}
六、重定向构造函数
有时候一个构造函数会调动类中的其他构造函数。 一个重定向构造函数是没有代码的,在构造函数声明后,使用 冒号调用其他构造函数。
class Point {
num x;
num y;
// The main constructor for this class.
Point(this.x, this.y);
// Delegates to the main constructor.
Point.alongXAxis(num x) : this(x, 0);
Point.alongYAxis(num y) : this(0, y);
Point.origin() : this(0, 0);
}
七、运算符重载
下表中的操作符可以被覆写。 例如,如果你定义了一个 Vector 类, 你可以定义一个 + 函数来实现两个向量相加。
< + | [] > / ^ []= <= ~/ & ~ >= * << == – % >>
下面是覆写了 + 和 - 操作符的示例:
class Vector {
final int x;
final int y;
const Vector(this.x, this.y);
/// Overrides + (a + b).
Vector operator +(Vector v) {
return new Vector(x + v.x, y + v.y);
}
/// Overrides - (a - b).
Vector operator -(Vector v) {
return new Vector(x - v.x, y - v.y);
}
}
main() {
final v = new Vector(2, 3);
final w = new Vector(2, 2);
print(v + w) // v + w == (4, 5)
print(v - w) // v - w == (0, 1)
}
八、重写对象的hashCode
在 Dart 中每个对象会默认提供一个整数的哈希值, 因此在 map 中可以作为 key 来使用, 重写 hashCode
的 getter 方法来生成自定义哈希值。 如果重写 hashCode
的 getter 方法,那么可能还需要重写 ==
运算符。 相等的(通过 ==
)对象必须拥有相同的哈希值。 哈希值并不要求是唯一的, 但是应该具有良好的分布形态。。
class Person {
final String firstName, lastName;
Person(this.firstName, this.lastName);
// 重写 hashCode
@override
int get hashCode {
return firstName.hashCode + lastName.hashCode;
}
// 如果重写了 hashCode,通常应该从新实现 == 操作符。
@override
bool operator ==(dynamic other) {
if (other is! Person) return false;
return (other.firstName == firstName && other.lastName == lastName);
}
}
void main() {
var p1 = Person('Bob', 'Smith');
var p2 = Person('Bob', 'Smith');
print(p1.hashCode == p2.hashCode); // true
print(p1 == p2); // true
}