第七節(jié): Dart中抽象類(lèi)abstract/接口implements/混入Mixin

Dart 語(yǔ)法學(xué)習(xí)目錄

第一節(jié): Dart 語(yǔ)法了解,認(rèn)識(shí)變量,常量,數(shù)據(jù)類(lèi)型
第二節(jié): Dart 操作符(運(yùn)算符)
第三節(jié): Dart 中流程控制,條件判斷以及循環(huán)語(yǔ)句
第四節(jié): Dart 中常用集合 List/Map
第五節(jié): Dart 函數(shù)使用,聲明函數(shù)/匿名函數(shù)/可選參數(shù)/作用域/閉包
第六節(jié): Dart 面向?qū)ο?構(gòu)造函數(shù)/靜態(tài)屬性
第七節(jié): Dart中抽象類(lèi)abstract/接口implements/混入Mixin
第八節(jié): Dart中泛型/泛型定義與使用
第九節(jié): Dart 中的庫(kù)/自定義庫(kù)/內(nèi)置庫(kù)/第三方庫(kù)


1. Dart中的抽象類(lèi)和抽象方法

1.1 定義抽象類(lèi)

dart中的抽象類(lèi)主要用于定義標(biāo)準(zhǔn), 子類(lèi)可以繼承抽象類(lèi), 也可以實(shí)現(xiàn)抽象類(lèi)的接口

定義抽象類(lèi)

  1. 抽象類(lèi)通過(guò)abstract關(guān)鍵字類(lèi)定義
  2. 抽象類(lèi)不能被實(shí)例化
// 定義抽象類(lèi)
abstract class Animate{

}

// 入口函數(shù)
void main(){
    //  實(shí)例化抽象類(lèi)就報(bào)錯(cuò)
    var cat = new Animate();

}


1.2 抽象方法

抽象方法的定義

  1. Dart中沒(méi)有方法體的方法我們稱(chēng)為抽象方法:
  2. Dart中的抽象方法不能用abstract聲明,

示例

抽象類(lèi)中的抽象方法

// 定義抽象方法
abstract class Animate{

    // 抽象方法
    // 抽象方法不能使用abstract聲明
    // 如果使用就會(huì)報(bào)錯(cuò)
    void eat();
}

非抽象類(lèi)中定義抽象方法就會(huì)報(bào)錯(cuò),

class Dog{
  // 屬性
  String name = "哈士奇";
  
  // 方法
  void getInfo(){
    print("我是${name}");
  }
  
  // 抽象方法
  void sayHello();  // 報(bào)錯(cuò)

}

所以不要在非抽象類(lèi)中定義抽象方法


1.3 抽象類(lèi)的說(shuō)明
  1. 如果子類(lèi)繼承抽象類(lèi)必須的實(shí)現(xiàn)里面的抽象方法
  2. 如果抽象類(lèi)被當(dāng)做接口實(shí)現(xiàn)的話(huà), 子類(lèi)必須得實(shí)現(xiàn)抽象類(lèi)里面定義的所有屬性和方法
  3. 抽象類(lèi)不能被實(shí)例化,只有繼承它的子類(lèi)可以
  4. 抽象類(lèi)通常用來(lái)定義接口,
  5. 抽象類(lèi)通常具有 抽象方法
  6. 有抽象方法的類(lèi)一定要聲明為抽象類(lèi)。


使用示例

// 定義一個(gè)抽象類(lèi)
abstract class Animal{

    // 抽象方法
    eat();
}

// 子類(lèi)繼承抽象類(lèi)
class Dog extends Animal{
    String name;
    Dog(this.name){}

    // 子類(lèi)必須實(shí)現(xiàn)抽象類(lèi)的方法
    @override
    eat() {
        print("${this.name}喜歡吃骨頭");
    }
}

// 子類(lèi)繼承抽象類(lèi)
class Cat extends Animal{
    String name;
    Cat(this.name){}

    // 子類(lèi)必須實(shí)現(xiàn)抽象類(lèi)的方法
    @override
    eat() {
        print("${this.name}喜歡吃千層餅");
    }
}

void main(){
    Dog dog = new Dog("哈士奇");
    dog.eat();  // 哈士奇喜歡吃骨頭

    Cat cat = new Cat("加菲貓");
    cat.eat();  // 加菲貓喜歡吃千層餅
}


1.4 抽象類(lèi)也可以有非抽象方法

抽象類(lèi)里也可以定義非抽象方法, 這些方法都可以被子類(lèi)多調(diào)用

// 定義一個(gè)抽象類(lèi)
abstract class Animal{

    // 抽象方法
    eat();

    // 非抽象方法
    printInfo(){
        print("我就是抽象類(lèi)里的一個(gè)非抽象方法");
    }
}

// 子類(lèi)繼承抽象類(lèi)
class Dog extends Animal{
    String name;
    Dog(this.name){}

    // 子類(lèi)必須實(shí)現(xiàn)抽象類(lèi)的方法
    @override
    eat() {
        print("${this.name}喜歡吃骨頭");
    }
}

// 子類(lèi)繼承抽象類(lèi)
class Cat extends Animal{
    String name;
    Cat(this.name){}

    // 子類(lèi)必須實(shí)現(xiàn)抽象類(lèi)的方法
    @override
    eat() {
        print("${this.name}喜歡吃千層餅");
    }
}

void main(){
    Dog dog = new Dog("哈士奇");
    dog.eat();  // 哈士奇喜歡吃骨頭

    // 子類(lèi)調(diào)用繼承的抽象類(lèi)中的非抽象方法
    dog.printInfo();  // 我就是抽象類(lèi)里的一個(gè)非抽象方法

    Cat cat = new Cat("加菲貓");
    cat.eat();  // 加菲貓喜歡吃千層餅
    dog.printInfo();  // 我就是抽象類(lèi)里的一個(gè)非抽象方法
}


2. 多態(tài)

2.1 正常使用的多態(tài)

多態(tài)就是父類(lèi)定義一個(gè)方法不去實(shí)現(xiàn),讓繼承他的子類(lèi)去實(shí)現(xiàn), 每個(gè)子類(lèi)有不同的表現(xiàn)

其實(shí)剛剛講的抽象類(lèi)的示例就是一個(gè)多態(tài), 父類(lèi)定義eat方法, 但是沒(méi)有實(shí)現(xiàn)他, 不同的子類(lèi)實(shí)現(xiàn)了eat方法的不同功能,這就是多態(tài)


2.2 子類(lèi)的實(shí)例賦值給父類(lèi)的引用

Dart 中的多態(tài) 講子類(lèi)類(lèi)型的指針賦值給父類(lèi)類(lèi)型的指針,同一個(gè)函數(shù)調(diào)用會(huì)有不同的執(zhí)行效果

// 定義一個(gè)抽象類(lèi)
abstract class Animal{
    // 抽象方法
    eat();
}

// 子類(lèi)繼承抽象類(lèi)
class Dog extends Animal{
    String name;
    Dog(this.name){}

    // 子類(lèi)必須實(shí)現(xiàn)抽象類(lèi)的方法
    @override
    eat() {
        print("${this.name}喜歡吃骨頭");
    }
    
    // 子類(lèi)自己的方法
    run(){
        print("${this.name}在愉快的奔跑");
    }
}


void main(){
    // 通過(guò)子類(lèi) 定義實(shí)例
    //  Dog dog = new Dog("哈士奇");
    //  dog.eat();  // 哈士奇喜歡吃骨頭
    //  dog.run();  // 哈士奇在愉快的奔跑

    // 將子類(lèi)的實(shí)例賦值給了父類(lèi)的引用
    Animal dog = new Dog("哈士奇");
    dog.eat();  // 哈士奇喜歡吃骨頭
    //  dog.run();  // 這個(gè)時(shí)候就報(bào)錯(cuò)

}

我們會(huì)發(fā)現(xiàn)如果將子類(lèi)的實(shí)例賦值給了父類(lèi)的引用, 那么將只能使用父類(lèi)限定的方法, 子類(lèi)自己實(shí)現(xiàn)的自定義的方法將不能調(diào)用


3. Dart中的接口

3.1 dart 接口了解

官網(wǎng)的定義

一個(gè)類(lèi)通過(guò)使用關(guān)鍵字implements 來(lái)實(shí)現(xiàn)一個(gè)或者多個(gè)接口。


接口說(shuō)明:

  1. 通類(lèi)和抽象類(lèi)都可以作為接口,類(lèi)就是接口
  2. 一個(gè)普通類(lèi)要實(shí)現(xiàn)某個(gè)接口,覆寫(xiě)接口接口類(lèi)(普通或抽象類(lèi))的每個(gè)成員。
  3. 如果是復(fù)用已有類(lèi)的接口,使用繼承(extends)。
  4. 如果只是使用已有類(lèi)的外在行為,使用接口(implements)。
  5. 每個(gè)類(lèi)都隱式的定義了一個(gè)包含所有實(shí)例成員的接口


3.2 普通類(lèi)接口
3.2.1 定義普通類(lèi)

通過(guò)class關(guān)鍵字定義普通類(lèi)

class Person{
    // 屬性
    String name;

    // 構(gòu)造函數(shù)
    Person(this.name);

    // 方法
    void sayHello(){
        print("大家好,我叫${name}");
    }
}

void main(){
    Person xm = new Person("小明");
    xm.sayHello();  //大家好,我叫小明
}


3.2.2 extends關(guān)鍵字實(shí)現(xiàn)類(lèi)的繼承

定義子類(lèi)繼承這個(gè)父類(lèi)

// 父類(lèi)
class Person{
    // 屬性
    String name;

    // 構(gòu)造函數(shù)
    Person(this.name);

    // 方法
    void sayHello(){
        print("大家好,我叫${name}");
    }
}

// 子類(lèi)通過(guò)extends 繼承父類(lèi)的方法
class Student extends Person{
    String name;
    Student(this.name):super(name);

    // 子類(lèi)自己的方法
    void getInfo(){
        print("他叫做${name}");
    }
}


void main(){


    Student xm = new Student("小明");
    xm.sayHello();  //大家好,我叫小明
    xm.getInfo();   // 他叫做小明
}


3.2.3 implements關(guān)鍵字實(shí)現(xiàn)接口

現(xiàn)在將父類(lèi)作為接口,讓子類(lèi)來(lái)實(shí)現(xiàn)這個(gè)接口

// 接口類(lèi)
class Person{
    // 屬性
    String name;

    // 構(gòu)造函數(shù)
    Person(this.name);

    // 方法
    void sayHello(){
        print("大家好,我叫${name}");
    }
}

// 實(shí)現(xiàn)接口類(lèi)
class Student implements Person{
    // 覆寫(xiě)接口的屬性
    @override
    String name;
    Student(this.name);

    // 覆寫(xiě)接口的方法
    @override
    void sayHello(){
        print("大家好,我叫${name}");
    }

    // 子類(lèi)自己的方法
    void getInfo(){
        print("他叫做${name}");
    }
}


void main(){
    Student xm = new Student("小剛");
    xm.sayHello();  //大家好,我叫小剛
    xm.getInfo();   // 他叫做小剛
} 

這個(gè)時(shí)候我們就會(huì)發(fā)現(xiàn), 這是不是子類(lèi)繼承父類(lèi)的關(guān)系,而是父類(lèi)就是定義接口,實(shí)現(xiàn)接口的子類(lèi)要覆寫(xiě)接口中的所有屬性和方法.


3.3 抽象類(lèi)接口

建議:

將抽象類(lèi)作為接口使用(類(lèi)就是接口),讓子類(lèi)來(lái)實(shí)現(xiàn)(關(guān)鍵字implements來(lái)實(shí)現(xiàn))

因?yàn)槌橄箢?lèi)的所有的方法不用定義方法體, 而普通類(lèi)定義的方法需要實(shí)現(xiàn)方法體, 反正這些方法在作為接口的時(shí)候都是需要被實(shí)現(xiàn)接口的子類(lèi)覆寫(xiě)的,那么有沒(méi)有方法體已經(jīng)不重要了,所以推薦使用抽象類(lèi)作為接口

// 定義一個(gè)抽象類(lèi)接口
abstract class Db{
    String uri;
    // 抽象方法
    add(String data);
    save();
    delete();
}

// Mysql 實(shí)現(xiàn)接口
class Mysql extends Db{
    @override
    String uri;
    Mysql(this.uri);

    // 子類(lèi)必須實(shí)現(xiàn)抽象類(lèi)的方法
    @override
    add(data){
        print("這是Mysql的${data}");
    }
    @override
    save(){
        print("這是Mysql的save方法");
    }
    @override
    delete(){
        print("這是Mysql的delete方法");
    }
}


void main(){
    Mysql mysql = new Mysql("mysql");
    mysql.add("123456");  // 這是Mysql的123456
    mysql.save();   // 這是Mysql的save方法
    mysql.delete();  // 這是Mysql的delete方法
}


4. Dart中一個(gè)類(lèi)實(shí)現(xiàn)多個(gè)接口

extends 關(guān)鍵字的繼承沒(méi)發(fā)做到多繼承,如果需要繼承多個(gè)類(lèi), extends是不能實(shí)現(xiàn)的,

那么我們就可以把需要繼承的類(lèi)作為接口,使用關(guān)鍵字implements來(lái)實(shí)現(xiàn)多個(gè)接口


還是要注意區(qū)分

  1. extends 是繼承 就算有些父類(lèi)的方法不覆寫(xiě),子類(lèi)的實(shí)例也能使用父類(lèi)的方法
  2. implements 是實(shí)現(xiàn)接口,不管實(shí)現(xiàn)多少父類(lèi)接口, 父類(lèi)里的所有方法都需要覆寫(xiě)的,

實(shí)現(xiàn)多接口的示例:

// 抽象類(lèi)A接口
abstract class A{
    String name;

    // 抽象方法
    printA();
}

// 抽象類(lèi)B接口
abstract class B{
    int age;

    // 抽象方法
    printB();
}


// Student 類(lèi)實(shí)現(xiàn) A和B 兩個(gè)接口
class Student implements A,B{
    // 覆寫(xiě)接口的屬性
    @override
    String name;
    int age;
    Student(this.name,this.age);

    // 實(shí)現(xiàn)A接口的方法
    @override
    void printA(){
        print("實(shí)現(xiàn)A接口的方法");
    }
    // 實(shí)現(xiàn)B接口的方法
    @override
    void printB(){
        print("實(shí)現(xiàn)B接口的方法");
    }

    // 子類(lèi)自己的方法
    void sayHello(){
        print("大家好, 我叫${name},今年${age}歲了");
    }
}

// 入口函數(shù)
void main(){
    // 實(shí)例化子類(lèi)

    Student xm = new Student("小剛",8);
    xm.printA();   // 實(shí)現(xiàn)A接口的方法
    xm.printB();   // 實(shí)現(xiàn)B接口的方法
    xm.sayHello();  //大家好, 我叫小剛,今年8歲了

} 


5. 枚舉類(lèi)型

枚舉類(lèi)型也稱(chēng)為 enumerationsenums , 是一種特殊的類(lèi),用于表示數(shù)量固定的常量值。


說(shuō)明:

  1. 使用 enum 關(guān)鍵字定義一個(gè)枚舉類(lèi)型.
  2. 枚舉是一種有窮序列集的數(shù)據(jù)類(lèi)型。
  3. 常用于代替常量,控制語(yǔ)句等
  4. 枚舉中的每個(gè)值都有index,返回索引,索引從0開(kāi)始.
  5. 枚舉中的每個(gè)值可以使用values 屬性列舉出來(lái)

枚舉的限制:

  1. 枚舉不能被子類(lèi)化,混合或?qū)崿F(xiàn)。
  2. 枚舉不能被顯式實(shí)例化。
// 定義枚舉
enum Color {
    red,
    green,
    blue,
    // 不能指定值,會(huì)報(bào)錯(cuò)的
    //    whie = "#fff"

}

// 入口函數(shù)
void main(){
    // index 獲取索引
    print(Color.red.index);  
    print(Color.green.index);
    print(Color.blue.index);

    // value
    print(Color.red);

    // 枚舉值
    List list = Color.values;
    print(list); //[Color.red, Color.green, Color.blue]


    // 流程控制
    var color = Color.red;

    switch(color){
        case Color.red:
            print("紅色");
            break;
        case Color.green:
            print("綠色");
            break;
        case Color.blue:
            print("藍(lán)色");
            break;
    }
} 


6. Mixin 混入

官方定義:

Mixin 是復(fù)用類(lèi)代碼的一種途徑, 復(fù)用的類(lèi)可以在不同層級(jí),之間可以不存在繼承關(guān)系。

簡(jiǎn)單說(shuō)就是在類(lèi)中混入其他的功能,實(shí)現(xiàn)類(lèi)似多繼承的功能


說(shuō)明:

  1. 使用mixin關(guān)鍵字替換class定義混入類(lèi)
  2. 作為Mixin的類(lèi)只能繼承Object,不能繼承其他的類(lèi)
  3. Mixin 類(lèi)似于多繼承,實(shí)在多類(lèi)繼承中重用一個(gè)類(lèi)代碼的方式。
  4. 作為mixins的類(lèi)不能聲明構(gòu)造函數(shù),不能調(diào)用 super
  5. 一個(gè)類(lèi)可以混入多個(gè)Mixin類(lèi)
  6. 使用with 方法實(shí)現(xiàn)類(lèi)似于多繼承
  7. mixins絕不是繼承 也不是接口, 而是一種全新的特性


6.1 混入普通的類(lèi)

使用關(guān)鍵字with混入普通的類(lèi)

// 定義普通混入類(lèi)
class A{
    String name = "AA";
printA(){
    print("這是普通類(lèi)A");
}
}

class B{
    String name = "BB";
printB(){
    print("這是普通類(lèi)B");
}
}

// 混入兩個(gè)類(lèi)A,B
class Student with A,B{

}

// 入口函數(shù)
void main(){
    // 實(shí)例化子類(lèi)
    Student student = new Student();
    print(student.name);  // BB
    student.printA();     // 這是普通類(lèi)A
    student.printB();    // 這是普通類(lèi)B

} 

在混入多個(gè)類(lèi)是,類(lèi)中有相同 的屬性或方法,后混入的會(huì)將先混入的覆蓋掉


6.2 使用mixin定義混入類(lèi)
// 使用mixin關(guān)鍵字定義混入類(lèi)
mixin A{
    String name = "AA";
    printA(){
        print("這是普通類(lèi)A");
    }
}

mixin B{
    String name = "BB";
    printB(){
        print("這是普通類(lèi)B");
    }
}

class Student with A,B{

}

// 入口函數(shù)
void main(){
    // 實(shí)例化子類(lèi)
    Student student = new Student();
    print(student.name);  // BB
    student.printA();     // 這是普通類(lèi)A
    student.printB();    // 這是普通類(lèi)B

} 


6.3 注意混入的類(lèi)不能有構(gòu)造函數(shù)

無(wú)論是class定義的混入類(lèi),還是mixin定義的混入類(lèi), 有構(gòu)造函數(shù)就不錯(cuò)

但是如果class定義的類(lèi)不作為混入類(lèi)使用,就不會(huì)報(bào)錯(cuò)

// 混入類(lèi)不能有構(gòu)造函數(shù)會(huì)報(bào)錯(cuò)

// mixin 定義的混入類(lèi)
mixin A{
    String name = "AA";
    //   A(this.name);  // 報(bào)錯(cuò)
    printA(){
        print("這是普通類(lèi)A");
    }
}


// class定義的混入類(lèi)
class B{
    String name = "BB";
    // B(this.name);   // 報(bào)錯(cuò)
    printB(){
        print("這是普通類(lèi)B");
    }
}

// 混入類(lèi)
class Student  with A,B{
}


6.4 混入類(lèi)不能繼承其他類(lèi)
// 被繼承的類(lèi)
class Person{
    int age ;
    Person(this.age);

    printInfo(){
        print("被繼承的類(lèi)Person, 年紀(jì)${this.age}");
    }
}

// B 是混入類(lèi),不能繼承其他類(lèi), 報(bào)錯(cuò)
class B extends Person{
    printB(){
        print("混入類(lèi)B");
    }
}


// 混入
class Student with B{

}


6.5 混入不影響繼承
// 第一個(gè)類(lèi)
mixin A{
    String name = "AA";
    printA(){
        print("這是普通類(lèi)A");
    }
}

class B{
    String name = "BB";
    printB(){
        print("這是普通類(lèi)B");
    }
}

// 被繼承的類(lèi)
class Person{
    int age ;
    Person(this.age);

    printInfo(){
        print("被繼承的類(lèi)Person, 年紀(jì)${this.age}");
    }
}


// 繼承一個(gè)類(lèi)混入兩個(gè)類(lèi)
class Student extends Person with A,B{
    Student(int age):super(age);
}


void main(){
    // 實(shí)例化類(lèi)
    Student student = new Student(18);
    // 繼承類(lèi)
    student.printInfo(); // 被繼承的類(lèi)Person, 年紀(jì)18

    // 混入類(lèi)的方法
    print(student.name);  // AA
    student.printA(); // 這是普通類(lèi)A
    student.printB(); // 這是普通類(lèi)B
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容