继承

  • 使用关键字 extends 继承一个类
  • 子类会继承父类可见的属性和方法,不会继承构造方法
  • 子类能够复写父类的方法,getter 和 setter
  • 单继承,多态性

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Person{
String name;
int age;

// 计算属性
bool get adult => this.age > 18;

// 私有属性,对于子类不可见
String _birthday;

void run(){
print("Person running...");
}
}

子类访问父类中的属性和方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Student extends Person{
void study(){
print("Student studying...");
}
}

void main(){
Student student = new Student();
// 调用 子类自己的方法
student.study(); // Student studying...

// 访问 父类中的属性
student.age = 20;

// 调用 父类的方法
student.run(); // Person running...

// 访问 父类的计算属性
print(student.adult); // true
}

覆盖父类的方法以及属性

和 java 中类似,使用 @override 表示覆写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Student extends Perosn{
// 覆写父类的计算属性
bool get adult => this.age > 15;

void study(){
print("Student studying...");
}

@override
void run() {
// 调用父类的方法
super.run();
print("student running...");
}
}

void main(){
Student student = new Student();
student.age = 16;
student.run(); // Person running... student running...
print(student.adult); // true

}

继承中多态的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Student extends Person{
void study(){
print("Student studying...");
}

@override
void run() {
// 调用父类的方法
super.run();
print("student running...");
}
}

void main(){
Person person = new Student();
// error: 这里无法访问到 子类的方法,因为使用多态生成的对象是 Person,Person 中没有 study方法
// person.study();

// 使用 is 表示将 person 转换为了 Student,下面就可以访问了
if (person is Student) {
person.run();
person.study();
}
}

继承中的构造方法

  • 子类的构造方法默认会调用父类的无名无参构造方法
  • 如果父类没有无名无参构造方法,则需要显示调用父类的构造方法
  • 在构造方法参数后使用 : super(arg) 显示调用父类构造方法,使用:this(arg)调用自己的其他构造方法(也可以是带名字的构造方法)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void main() {
var student = new Student("name"); // object
}

class Person{
String name;

// 父类中的构造器
Person(this.name);
Person.withName(this.name){
print("object");
}
}

class Student extends Person{
// 使用 : super 调用父类的构造方法
// Student(String name) : super(name); 这种写法与下面的写法一致
Student(String name) : super.withName(name);
}

构造方法执行顺序

  • 父类的构造方法在子类构造方法体开始执行的位置调用
  • 如果有初始化列表,初始化列表会在父类构造方法之前执行

子类的构造方法初始化列表,必须要在父类初始化列表之前,否则就会报错。

抽象类

  • 使用 abstract class ClassName 创建抽象类

  • 抽象类里面的抽象方法是不实现的(可以有非抽象方法),由子类进行实现,@override关键词,一般用于来约束子类,制定标准。

  • 同样抽象类不能实例化,里面的属性和实现的方法,只能通过子类去访问,但是可以通过子类的实例赋值给父类的引用实现

  • 继承抽象类是用来约束子类,接口实现抽象类是用来制定标准

接口

  • 使用 implements关键词
  • 实现接口,不仅要实现抽象类的属性还要实现抽象类的方法(extends不需要再写一遍属性)

混入(mixin)

Dart中的Mixins通过创建一个新类来实现,该类将mixin的实现层叠在一个超类之上以创建一个新类 ,它不是“在超类中”,而是在超类的“顶部”,因此如何解决查找问题不会产生歧义。— Lasse R. H. Nielsen on StackOverflow.

  • 关键词withclass A with B, C, D,后面会覆盖前面
  • 可以实现多接口
  • 函数命名冲突: 遇到相同功能的函数,最后载入的会覆盖之前的函数定义(如果子类没有重写的话),即最后一个继承的类的方法

参考: