Dart:类

Object
  • Object是所有类的父类。
  • Object没有父类。
  • 一个类只能有一个父类。
  • 如果一个类没有显示的用extends去继承一个类,那么默认其继承的是Object。
类概述
  • 普通类

    1. 变量

      • 实例变量(创建对象后,使用 对象.变量名 调用)
      • 静态变量(用static修饰,使用 类名.变量名 调用)
    2. 函数

      • 实例函数(创建对象后,使用 对象.函数名 调用)
      • 静态函数(用static修饰,使用 类名.函数名 调用)
    3. 构造函数

      • 默认构造函数
      • 自定义构造函数
      • 静态构造函数(使用const修饰的构造函数)
      • 重定向构造函数
      • 工厂构造函数
  • 抽象类

    1. 变量

      • 实例变量(其子类创建对象后,使用 对象.变量名 调用)
      • 静态变量(用static修饰,使用 类名.变量名 调用)
    2. 函数

      • 实例函数(其子类创建对象后,使用 对象.函数名 调用)
      • 静态函数(用static修饰,使用 类名.函数名 调用)
      • 抽象函数(其子类实现该函数,创建对象后,使用对象.函数名
        调用)
    3. 不能实例化(工厂构造函数除外)。

普通类

声明

1
2
3
4
5
6
7
8
9
10
11
12
13
class Class01{
//变量
int a;
String b;
var c = 3;
//函数
void fun01(int d){
//...
}
String fun02(){
return b;
}
}

创建类的实例,使用new
或const,new对应的是普通的构造函数,const对应的是用const形式的构造函数。

1
var class01 = new Class01();

调用实例的属性或函数,使用 . 号

1
2
print(class01.c);
class01.fun02();

级联操作符 .. , 可以连续调用对象的一些列属性或函数。

1
2
3
4
5
6
7
var class02 = new Class01();
class02
..a = 1
..b = "a"
..c = 33
..fun02()
..fun01(1);
构造函数:
  • 没有返回值(factory构造方法有返回值)
  • 构造函数名与类名相同

默认构造函数,如果类中没有显示声明构造函数,那么会默认有个构造函数,默认构造函数是与类同名且无参数无返回值的函数。

1
2
3
4
5
6
class Class01{
//变量
int a;
String b;
//未声明构造函数
}

所以这个类默认有个构造函数

1
Class01(){}

所以可以使用 new Class01() 来创建实例。

自定义构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
class Class02{
int a;
String b;
//自定义的一个构造函数,有两个参数
Class02(int a,String c){
this.a = a;//名字冲突时,可使用 this
b = b;
}
}
void main(){
var c02 = new Class02(3,"abc");
print(c02.a);
}

如果构造函数中的参数都是给实例变量赋值的,那么上面这种情况还可以写成下面这种方式,简化了:

1
2
3
4
5
6
7
8
9
10
class Class02{
int a;
String b;
//自定义的一个构造函数,有两个参数
Class02(this.a,this.b);
}
void main(){
var c02 = new Class02(3,"abc");
print(c02.a);
}

命名构造函数,一种可以为类声明多个构造函数的方式。注意这里没有重载的概念,不能声明只是参数类型或数量不同的构造函数,使用命名构造函数实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Class03{
int a;
String b;
Class03(int a,String b){
this.a = a;
this.b = b;
}
Class03.fun1(int a){
this.a = a;
}
Class03.fun2(String b){
this.b = b;
}
}
void main(){
var class03 = new Class03(3, "ccc");
var class04 = new Class03.fun1(4);
var class05 = new Class03.fun2("ddd");
}

静态构造函数

  • 类的对象不会改变
  • 类的变量不会改变,也就是常量了
  • 使用final修饰变量
  • 使用const 修饰构造方法
  • 创建实例时,使用const 而不是new
1
2
3
4
5
6
7
8
9
10
11
12
13
class Class04{
final int a;
final String b;
const Class04(this.a,this.b);
void fun01(){
print("aa");
}
}
void main(){
var class06 = const Class04(4, "ccc");
class06.fun01();
print(class06.a);
}

重定向构造函数,在类的构造函数中,有时我们只是需要调用到另一个构造函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Class05{
int a;
String b;
Class05(int a,String b){
this.a = a;
this.b = b;
}
Class05.fun1(int a){
this.a = a;
}
Class05.fun2(String b):this.fun1(33);//重定向到fun1
Class05.fun3(String b):this(33,"ddddd");//重定向到构造函数
}

工厂构造函数

  • 使用factory修饰构造函数
  • 构造函数内有返回值,类型是当前类或其子类,此返回值可以是用命名构造函数创建的,也可以是缓存中的。
  • 使用new创建实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Class06{
int a;
static Class06 instance ; //这里创建了一个单例
factory Class06(int a){//这里的构造函数用factory修饰,使用new时,不再是创建一个全新的实例了,而是通过函数体内return获取到实例
if(instance==null){
instance = new Class06.fun1(a);
}
return instance;
}
Class06.fun1(this.a);//注意这里是实例化当前对象的构造方法
}

void main(){
var class07 = new Class06(3);//使用new
print(class07.a);
}
set get方法
  • 使用 set get修饰属性
  • 该属性不是真实存在,而是类似于一个函数,该函数内可以对类的其他属性和方法进行操作。
  • 读取该属性值时 调用的get
  • 对该属性赋值时,调用的set
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Class08{
int hands;
int feet;

num get persons => hands / 2;
set persons(num n){
hands=n*2;
feet=n*2;
}
}
volid main(){
var class08 = new Class08();
class08.persons = 3;//这里就调用了set方法,进而对hands feet赋值了
print(class08.hands);
}
抽象类
  • 使用abstract修饰类。
  • 可定义实例方法。
  • 可定义抽象方法,抽象方法没有函数体。
  • 抽象类不能实例化(工厂构造函数除外)。
  • 子类继承抽象类后,必须实现所有抽象方法,除非子类也是抽象类。
  • 只有抽象类能定义抽象方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//定义抽象类
abstract class Class09{
void fun01();//定义抽象方法
}
//继承抽象类
class Class10 extends Class09{
@override
void fun01() {//实现抽象方法
print("aaa");
}
}
void main(){
var c10 = new Class10();
c10.fun01();
}
静态变量和静态函数
  • 使用static修饰的变量为静态变量。
  • 使用static修饰的函数为静态函数。
  • 静态变量和函数,使用类名直接调用。
  • 实例变量和函数,使用类的对象调用。
  • 静态变量和函数,不能访问实例变量和函数。
  • 静态函数内,不能使用this。
  • 普通类和抽象类都可以定义静态变量和函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Class11{
static int a = 3;//静态变量
int b = 4;//实例变量

//静态方法
static void fun01(int c){
print(c);
//print(b);//这里报错,静态方法内不能使用实例变量
}
//实例方法
void fun02(){
print(b);
}
}
void main(){
var class11 = new Class11();
//实例变量和函数
print(class11.b);
class11.fun02();
//调用静态变量和函数
Class11.fun01(44);
print(Class11.a);
}
枚举
  • 使用enum声明枚举。
  • 每个枚举值都有一个唯一值。
  • 枚举不能使用new实例化 。
  • 使用枚举值 枚举.枚举值。
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
53
54
55
//定义枚举
enum Week{
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}

//属性values 获取所有枚举值
List<Week> list = Week.values;

list.forEach((e){
print(e);//打印枚举
// Week.Monday
// Week.Tuesday
// Week.Wednesday
// Week.Thursday
// Week.Friday
// Week.Saturday
// Week.Sunday
});

list.forEach((e){
print(e.index);//属性index 表示该枚举值在定义时的序号
// 0
// 1
// 2
// 3
// 4
// 5
// 6
});

var day = Week.Friday;
switch(day){
case Week.Monday:
break;
case Week.Tuesday:
break;
case Week.Wednesday:
break;
case Week.Thursday:
break;
case Week.Friday:
break;
case Week.Saturday:
break;
case Week.Sunday:
break;
default:
break;
}
继承
  • 使用extends 关键字表示继承。
  • 构造方法不能被继承。
  • 使用@override重写函数。
  • 如果继承的是抽象类,要实现所有抽象函数。

继承抽象类

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
//定义抽象类
abstract class Parent{
int a = 1;
String b = "bb";
void fun1();//定义抽象方法
void fun2(int a,int c){
this.a = a;
print(c);
}
}
class Child extends Parent{
String b = "child b";//重写了父类的属性
//实现了父类的抽象函数
@override
void fun1() {
print(b);
}

//重写了父类的函数
@override
void fun2(int a, int c) {
print(a+c);
}
}

void main(){
var child = new Child();
child.fun1();// child b
child.fun2(3, 4); //7
}

继承普通类

  • 子类至少定义一个构造函数调用父类的任一构造函数,使用:super。
  • 子类的每个构造函数都要继承父类的任一构造函数。
  • 子类可重写父类的函数。
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
class Fruit{
String name;
int nums;
Fruit(this.name);//定义构造函数
Fruit.num(this.name,this.nums);//定义命名构造函数
Fruit.con(num){//定义命名构造函数
nums = num*2;
}
void fun1(){
print(name);
}
void fun2(){
print(nums);
}
}

class Apple extends Fruit{
String name;
int nums;
int color;
//至少需要定义一个构造函数调用父类的任一构造函数
Apple(String name) : super(name);
Apple.con1(this.color,this.name): super.num(name,3);
Apple.con2() : super.con(3){
color = 3;
}
//重写父类的fun2函数
@override
void fun2() {
print(color);
super.fun2();//调用父类的fun2方法
}
//子类自己的方法
void fun3(){
print(nums);
}
}
mixins
  • 类在Dart中只能继承一个父类。
  • mixin可理解为让类实现了继承多个父类的效果,但不是多继承,而是其目的是实现代码重用。

声明一个with类

  • 跟声明普通类一样的方式。
  • 区别在于,不声明构造函数,也不使用静态函数或变量。
  • 纯粹的属性和函数。

怎么使用?子类声明时

  • 后跟with+类名
  • with后可跟多个类,用“,”分开
    看个例子:
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
53
54
55
56
57
class With1 {
String getName() => 'With1';//三个类都有该方法
String getAge()=> "With1 10" ;//该类独有
}

class With2 {
String getName() => 'With2';//三个类都有该方法
String getColor() => "With2 red";//该类独有
int getNum()=> 6;//该类和OtherClass都有
String getFruit()=>"With2 banana";
}

class OtherClass {
String getName() => 'OtherClass';//三个类都有该方法
int getNum() => 3; //该类和With2都有
int getDesk() => 333;//该类独有

String getPhone()=>"OtherClass huawei";//该类和子类
String getFruit()=>"OtherClass apple";

}

class Child1 extends OtherClass with With1 ,With2 {
//重写父类
@override
String getPhone() {
return "Child1 iphone";
}
@override
String getFruit() {
return "Child1 oriange";
}
}
class Child2 extends OtherClass with With2, With1 {}

void main(){
print("class Child1 extends OtherClass with With1 ,With2 {}");
Child1 c1 = Child1();
print(c1.getPhone());//Child1 iphone 重写了函数,调用时用的是自身的函数
print(c1.getFruit());//Child1 oriange 重写了函数,调用时用的是自身的函数
print(c1.getDesk());//333 调用的是OtherClass的函数 With1 With2中没有同名函数
print(c1.getNum());//6 调用的是With2中的函数
print(c1.getAge());//With1 10 调用的是With1中的函数
print(c1.getColor());//With2 red 调用的是With2中的函数
print(c1.getName());//With2 调用的是With2中的函数 With2在声明顺序中更靠后

print("-----------------------");
print("class Child2 extends OtherClass with With2, With1 {}");
Child2 c2 = Child2();
print(c2.getPhone());//OtherClass huawei 没有重写函数,调用时用的是OtherClass的函数
print(c2.getFruit());//With2 banana 没有重写函数,调用时用的是With2的函数,虽然OtherClass也有,但With2在声明顺序中更靠后
print(c2.getDesk());//333 调用的是OtherClass的函数 With1 With2中没有同名函数
print(c2.getNum());//6 调用的是With2中的函数
print(c2.getAge());//With1 10 调用的是With1中的函数
print(c2.getColor());//With2 red 调用的是With2中的函数
print(c2.getName());//With1 调用的是With1中的函数 With1在声明顺序中更靠后
}

终极理解:

  • A extends B with C,D{}
  • A 继承了B
    并拥有了C和D所有的属性和函数,可以用A的实例直接调用CD的属性方法。
  • 如果B有函数fun1,A重写了这个函数
    那么以后A的实例调用的fun1,都是A重写后的方法。
  • 如果B有函数fun1,CD中也有函数fun1,A重写了这个函数
    那么以后A的实例调用的fun1,都是A重写后的方法。
  • 如果B有函数fun1,CD中也有函数fun1,A没有重写这个函数
    那么以后A的实例调用的fun1,是声明方法时最后的那个类的函数,比如“A
    extends B with C,D”,那么就是D中的fun1,如果是“A extends B with
    D,C”,那么就是C中的fun1。也就是说优先级是从后向前的(前提是子类没有重写函数)。
隐式接口
  • 与java不同,dart中没有专门定义接口的方式,dart中类即是接口。
  • 一个类可以实现多个接口,也就是可以实现多个类,用implements。
  • 一个类只能继承一个类,用extends。
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
class X {
int x= 19;
void funX(){
print("X-X");
}
}
class Y {
String y = "yyy";
void funY(){
print("Y-Y");
}
}
class Z implements X,Y{
@override
int x=33;
@override
String y="33333";

@override
void funX() {
print("Z-X");
}
@override
void funY() {
print("Z-Y");
}
}
  • Z 实现了类X Y ,那么Z中必须重写XY中所有的属性和函数。
-------------本文结束感谢您的阅读-------------
如果你喜欢这篇文章,可以请我喝一杯 Coffee ~