静态成员和非静态成员 , 对象操作符 , 类的继承 , 子类覆写 , 抽象类 , 接口 , 一个类实现多个接口 , Dart中的Mixins
Dart中的静态成员与非静态成员
使用static 关键词可定义静态属性和静态方法
静态方法不能访问非静态成员,非静态方法可以访问静态成员
类中非静态方法和属性必须实例化后访问,静态成员可以不用实例化也能访问
例1:静态成员与非静态成员
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18class Person{
static String name='张三'; //静态属性
int age=20; //非静态属性
static void show(){ //静态方法
print(name); //静态方法调用静态属性
}
void printInfo(){ //非静态方法
print(name); //非静态方法调用静态属性
print(age); //非静态方法调用非静态属性
show(); //非静态方法调用静态方法
}
}
main(){
Person p=Person(); //因有非静态成员所以要实例化
print(Person.name); //静态成员可不用实例化直接调用 输出: 张三
Person.show(); //也可实例化之后调用 输出: 张三
p.printInfo(); //非静态成员必须实例化后调用 输出: 张三 20 张三
}
对象操作符
Dart中的对象操作符有:
?条件运算符(了解) , as类型转换符 , is类型判定符 , ..级联操作符(连缀)
连缀的第一行不要添加分号,最后一行再加,可以省略相同的开头
例1:连缀的使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17import 'lib/person.dart'; //调用Person类
main(){
Person p=Person('张三', 20); //实例化Person类
p.getInfo(); //输出: 姓名:张三 年龄:20
p.name='李四';
p.age=40;
p.getInfo(); //输出: 姓名:李四 年龄:40
}
//可使用级联操作符进行简化
import 'lib/person.dart'; //调用Person类
main(){
Person p=Person('张三', 20); //实例化Person类
p..getInfo() //输出: 姓名:张三 年龄:20
..name='李四'
..age=40
..getInfo(); //输出: 姓名:李四 年龄:40
}
类的继承
子类可通过extends关键词来继承父类
子类会继承父类里可见的属性和方法,但不会继承构造函数
子类能覆写父类的方法和getter , setter
使用super关键词还可以给父类的命名构造函数传参
例1:子类继承父类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25class Person{
String name;
int age;
Person(this.name,this.age);
getInfo(){
print('$name,$age');
}
}
class Web extends Person{ //子类继承父类
Web(String name, int age,String sex) : super(name, age){ //子类构造函数,super是吧子类实例化时的数据赋给父类
this.sex=sex; //子类自己的属性赋予实例化关联
}
String sex; //子类可以定义自己的属性
void run(){ //子类可以定义自己的方法
print('姓名:$name 性别:$sex 年龄:$age');
}
}
main(){
var p=Person('张三', 20); //我们这里首先实例化了父类为p
p.getInfo(); //p输出: 张三,20
var w=Web('李四', 25, '女'); //随后实例化了子类为w
w.getInfo(); //子类可以调用父类的方法和属性,因为在实例化w的同时吧w实例化赋予的数据通过super传给了父类,所以这里调用父类的方法输出的是: 李四,25
w.run(); //子类可以调用自己的方法 输出: 姓名:李四 性别:女 年龄:25
p.getInfo(); //父类调用父类的方法,因为P实例化时传入数据是张三和20,这里输出的是p不是w不受子类传输的数据影响,所以输出依旧是: 张三,20
}例2:使用super关键词还可以给父类的命名构造函数传参
1
2
3
4
5
6
7
8
9Person.now(this.name,this.age){
print(DateTime.now());
}
//例如Person有一个Person.now的构造函数
Web.now(String name, int age,String sex) : super.now(name, age){
this.sex=sex;
}
//则继承之后再子类中也可以添加一个super.now的构造函数,实例化调用时也可以
var w=Web.now('李四', 25, '女');
子类覆写父类的方法
覆写就是在子类中使用和父类里同样名字的方法来重写方法
实例化子类后调用此方法时默认调用覆写后的方法
例1:覆写父类的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22class Person{
String name;
Person(this.name);
run(){
print(name); //父类方法
}
}
class Web extends Person{
String sex;
Web(String name,String sex) : super(name){
this.sex=sex;
}
//覆写方法时点击方法名点修复会自动显示,也可以手动输入,@override可以判断覆写方法名和父类方法名是否完全一致,不一致的话会报错
void run(){
print('姓名:$name 性别:$sex,正在打扫卫生'); //覆写的方法,在子类调用此方法时会优先调用子类覆写的方法
}
}
main(){
var w=Web('张三', '女');
w.run(); //调用子类的run方法输出: 姓名:张三 性别:女,正在打扫卫生
}使用super关键词可在子类的方法中调用父类的方法
例2:在子类中调用父类方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29class Person{
String name;
Person(this.name);
run(){
print(name);
}
work(){
print('正在工作中...'); //父类中方法work
}
}
class Web extends Person{
String sex;
Web(String name,String sex) : super(name){
this.sex=sex;
}
void run(){
print('姓名:$name 性别:$sex,正在打扫卫生');
super.work(); //在子类的方法中使用super.work来调用父类的方法
//work(); 可能是新版本的原因,似乎在Dart中现在不用super关键词也可以直接在子类中调用父类方法
}
}
main(){
var w=Web('张三', '女');
w.run(); //输出: 姓名:张三 性别:女,正在打扫卫生
// 正在工作中...
}
抽象类
Dart中的抽象类主要用于定义标准,子类可以继承抽象类,也可以实现抽象类接口
抽象类通过obstract关键词定义(声明)
Dart中的抽象方法不能用obstract声明,Dart中没有方法体的方法,我们称之为抽象方法
如果子类继承抽象类,那么必须要实现抽象类中的抽象方法
如果吧抽象类当做接口实现的话,必须要实现抽象类里定义的所有属性和方法
抽象类不可以实例化,只有继承它的子类可以实例化
多态的定义
- 多态就是父类定义的一个方法不实现,让继承他的子类实现,每个子类有不同的表现
- 子类继承父类抽象类的时候也可以有自己的普通方法,但如果想在实例化后只能调用父类的抽象类而不能用自己的普通类,可以吧子类的实例赋值给父类的引用,这就是普通意义上的多态(例2)
例1:定义一个抽象类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35abstract class Animal{ //抽象类,不可实例化
eat(); //抽象方法,子类必须实现
run();
printInfo(){ //抽象类中可以有一般方法
print('我是一个抽象类中的普通方法');
}
}
class Dog extends Animal{ //子类继承抽象类
eat(){ //子类覆写并实现父类的抽象方法
print('小狗吃骨头');
}
run(){
print('小狗RushB');
}
}
class Cat extends Animal{
eat(){
print('小猫吃老鼠');
}
run(){
print('小猫RushB');
}
}
main(){
Dog d=Dog(); //实例化子类,抽象类不可实例化
d.eat(); //输出: 小狗吃骨头
d.printInfo(); //输出: 我是一个抽象类中的普通方法
Cat c=Cat(); //多态的一种
c.eat(); //输出: 小猫吃老鼠
c.run(); //输出: 小猫RushB
}例2:把子类的实例赋值给父类的引用
1
2
3//在实例化时,吧子类的实例赋值给父类的引用
Animal d=Dog();
//这时候就只能调用Animal中的方法,不能调用Dog中的方法了
接口
Dart的接口没有interface关键字定义接口,而是普通类或抽象类都哦可以作为接口被实现,但和其他语言一样同样使用implements关键词进行实现
extends抽象类和implements的区别:
- 如果要使用抽象类里面的方法,并且要用抽象方法约束子类的话我们就用extends方法继承抽象类
- 如果只是吧抽象类当做标准的话,我们就用implements实现抽象类
如果实现的类是普通类,会将普通类或抽象类中的属性和方法全部覆写一遍
因为抽象类可以定义抽象方法,普通类不可以,所以如果要实现接口,一般会使用抽象类定义接口
例1:定义一个DB库,支持mysql , mssql , mongodb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53abstract class Db{ //当做接口,接口就是约定/规范
String url; //数据库的链接地址
add(date);
save();
delete();
}
class Mysql implements Db{
String url;
Mysql(this.url); //接口拥有自己的构造函数
add(date) {
print('这是mysql的add方法$date');
}
delete() {
}
save() {
}
}
class Mssql implements Db{
String url;
add(date) {
}
delete() {
}
save() {
}
}
class Mongodb implements Db{
String url;
add(date) {
}
delete() {
}
save() {
}
}
main() {
var mysql=Mysql('xxx');
mysql.add('123ddas'); //输出: 这是mysql的add方法123ddas
}
//一般情况下接口和方法会被抽离到单独文件,然后调用
一个类实现多个接口
一个类可通过implements关键词来实现多个接口,但同时要实现多个接口里所有的属性和方法
extends继承并不能同时实现多个接口
例1:定义两个接口,然后用一个来同时实现两个接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25abstract class A{
printA();
String name;
}
abstract class B{
printB();
}
class C implements A,B{ //C类同时实现A和B两个接口
String name; //必须同时实现两个类里所有的方法和属性
printA() {
print('A方法');
}
printB() {
print(name);
}
}
main() {
var c=C(); //实例化C类后可调用里面所有的方法和属性
c.name='张三';
c.printA(); //输出: A方法
c.printB(); //输出: 张三
}
Dart中的Mixins(混入)
在Dart中可以使用mixins的with关键词实现类似多继承的功能
作为mixins的类只能继承自object,不能继承其他类
- 指C如果要mixins A和B,则A和B必须是一个类,而不是继承自其他类的子类
作为mixins的类不能有构造函数
一个类可以mixins多个mixins类
mixins绝不是继承,也不是接口,而是一种全新的特性
如果实例化后要调用的方法在几个类中都有同名方法,则以with关键词后最后的类覆盖前面的类(例3)
例1:使用mixins的with关键词实现类似多继承
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24class A{ //被mixins的类中不能有构造函数
printA(){
print('A');
}
run(){
print('A Run');
}
}
class B{
printB(){
print('B');
}
run(){
print('B Run');
}
}
class C with B,A{ //C with B和A
}
main(){
var c=C();
c.printB(); //输出: B
c.printA(); //输出: A
}例2:一个类可以mixins多个mixins类,有两种方法,第一种直接mixins
1
2
3class C with Person,B,A{
}例3:第二种方法则可以首先使用C继承Person再mixins A和B 则父类Person中可以拥有构造函数,C中也要覆写Person的构造函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37class Person{
String name;
num age;
Person(this.name,this.age);
printInfo(){
print('$name,$age');
}
run(){
print('Person Run');
}
}
class A{
printA(){
print('A');
}
run(){
print('A Run');
}
}
class B{
printB(){
print('B');
}
run(){
print('B Run');
}
}
class C extends Person with B,A{ //可继承Person然后再WithB和A,则可以拥有Person的构造函数
C(String name, num age) : super(name, age);
}
main(){
var c=C('张三',20); //实例化时要传参
c.run(); //因为class C extends Person with B,A按顺序A在最后面,后面的覆盖前面的,所以输出: A Run
c.printA(); //输出: A
c.printInfo(); //这里调用了Person类父类的方法 输出: 张三,20
}