Dart語言學習(十二) Dart面向對象

Dart做爲一種高級語言,支持面向對象的不少特性,而且支持基於mixin的繼承方式。html

基於mixin的繼承方式是指:一個類能夠繼承自多個父類,至關於其餘語言裏的多繼承。編程

全部的類都有同一個基類Object,這和特性相似於Java、Objective-C 等語言,Java全部的類也都是繼承自Object,也就是說一切皆對象。json

 

//實例化了一個User類的對象user
var user = new User('Liming',25);
  • 實例化成員變量

Class User{
    String name;//name 成員變量
    int age;//age 成員變量
}

類定義中全部的變量都會隱式的定義setter方法,針對非空的變量會額外增長getter方法。ide

實例化成員變量請參考以下代碼:函數

void main(){
    var user = new User();
    user.name = 'Liming';//至關於使用了name的setter方法
    user.age = 25;
}
  • 構造函數

  1.常規的構造函數

構造函數是用來構造當前類的函數,是一種特殊的函數,函數名稱必需要和類名相同才行.學習

以下代碼爲User類添加了一個構造函數,函數裏給User類的兩個成員變量初始化了值:this

Class User{
    String name;
    int age;
    User(String mName,int mAge){
        this.name = mAge;
        this.age = mAge;
    }
}

this關鍵字指向了當前類的實例spa

上面的代碼能夠簡化爲:code

Class User{
    String name;
    int age;
    User(this.name,this.age);
}

第一種沒有簡化的構造方法初始化成員變量是在方法體內進行初始化的,htm

第二種簡化的構造方法初始化成員變量,是在實例化類的時候直接進行賦值初始化的。

  2.命名的構造函數

使用命名構造函數是 從另外一類或現有的數據中快速實現構造函數 ,代碼以下所示:

Class User{
    String name;
    int age;
    //普通構造函數
    User(this.name,this.age);

    //命名構造函數
    User.fromJson(Map json){
        name = json['name'];
        age = json['age'];
    }
}

//在實例化類的時候,若是沒有傳參,會默認調用無參數的構造方法
//普通構造函數
var user = new User('張三',25);

//命名構造函數
var user = new User.fromJson(mMapJson);

 

  3.子類的建立

注1:子類在繼承父類的時候,若是在父類中有顯示的提供一個無名、無參的構造函數,不會繼承父類無名有參構造函數和命名構造函數,即:子類只會繼承父類無名無參的構造函數。(程序會給類隱式的生成一個無名、無參的構造函數)

注2:子類在繼承父類的時候,若是在父類中沒有有顯示的提供一個無名、無參的構造函數,子類必須手動調用父類的一個構造函數,在這種狀況下,調用的父類的構造函數要放在子類構造函數以後,在子類構造函數體以前,用「:」分隔。

注3:父類的構造函數會在子類的構造函數前調用。

注4:默認狀況下,子類只能調用父類無名、無參數的構造函數。

注1和注3:父類中有一個無名、無參的構造函數,子類繼承父類,會默認繼承父類無名、無參的構造函數(即便有其餘無名、有參的構造函數或者命名構造函數,子類都不會調用),而且,父類的無名、無參的構造函數會在子類的構造函數以前被調用。

Class Futher {

    //無名、無參的構造函數
    Futher(){
        print('我是父類無名、無參的構造函數');
    }
}

Class Son extends Futher {
    //由於父類有顯式的聲明一個無名、無參的構造函數,因此不用手動調用父類的構造函數。
    Son.fromJson(Map mMapJson){
        print('我是子類的命名構造函數');
    }
}

var son = new Son.fromJson(mMapJson);
//打印結果
//我是父類無名、無參的構造函數
//我是子類的命名構造函

注2:下面代碼裏,子類的命名構造方法寫了兩種方式,第一種是正確的,第二種是錯誤的,有詳細的註釋, 若是有疑問請留言。

Class Futher {

    //無名、無參的構造函數
    Futher.printSth(){
        print('我是父類無名、無參的構造函數');
    }
}

Class Son extends Futher {
    //由於父類沒有有顯式的聲明一個無名、無參的構造函數,因此須要手動的調用父類的構造函數。
    Son.fromJson(Map mMapJson) : super Futher.printSth{
        print('我是子類的命名構造函數');
    }

    //這種寫法會報錯,由於父類中沒有顯示的提供一個無名、無參的構造函數。因此須要像上面那樣,手動調用父類的一個構造函數
    Son.fromJson(Map mMapJson){
        print('我是子類的命名構造函數');
    }
}

  4.構造函數初始化列表

上面在講解常規的構造函數和命名構造函數的時候,示例代碼都有對類中的成員變量進行了初始化,

特色是在構造函數的方法體內進行初始化,初始化成員變量還有另外一種方式,就是在構造函數運行前來初始化成員變量。

Class User {
    String name;
    int age;

    User(mName,mAge)
        :name = mName,
        age = mAge{
            // Do Some Thing
        }
}

特色是在構造函數的方法體前(大括號前面)來初始化成員變量,變量間用「,」分隔。

  • 讀取和寫入對象

get()和set()方法是專門用於讀取和寫入對象的屬性的方法,每個類的實例,系統都會隱式的包含有get()和set()方法。

例如,定義一個矩形的類,有上、下、左、右:top、bottom、left、right四個成員變量,使用get及set關鍵字分別對right、bottom進行獲取和設置值。代碼以下所示:

Class Rectangle {
    num left;
    num top;
    num width;
    num height;

    Rectangle(this.left,this.top,this.width,this.height);

    num get right => left + width;//獲取righht的值(第一行)

    set right(num value) => left = value - width;//設置right的值,同時left也發生了變化(第二行)

    num get bottom => top + height;//獲取bottom的值(第三行)

    set bottom(num value) => top = value - height;//設置bottom值,同時top也發生了變化(第四行)
}

void main(){
    var rect = new Rectangle(3,4,20,15);//實例化Rectangle,並給類中的4個變量進行初始化賦值

    print('left:'+rect.left.toString());//獲取left的值,並打印 left = 3
    print('right:'+rect.right.toString());//獲取right的值,並打印,這裏執行了Rectangle類中第一行代碼,right = left + width,right = 3+20 = 23
    rect.right = 30;//從新給right進行賦值 right = 30,這裏執行了Rectabgke類中的第二行代碼,將right的值設置爲30,而且,將left的值改成30 - 20,left = 30-20 = 10
    print('right的值改成30');
    print('left:'+rect.left.toString());//獲取left的值,並打印,由於上面給right從新賦值的時候,也改變了left的值,因此,此時left = 10
    print('right:'+rect.right.toString());//rect.right = 30將right的值改成了30,因此,right = 30


    print('top:'+rect.top.toString());
    print('bottom:'+rect.bottom.toString());
    rect.bottom = 50;
    print('bottom的值改成50');
    print('top:'+rect.top.toString());
    print('bottom:'+rect.bottom.toString());
}

//打印結果
left:3
right:23
right的值改成30
left:10
right:30
top:4
bottom:19
bottom的值改成50
top:35
bottom:50

上面的示例註釋已經解釋的很清楚了,若是有任何疑問,請留言!!!

這裏我就解釋一下「=>」的做用,在Dart裏面,你們能夠簡單的理解爲接下來要繼續執行後面的操做。

  • 重運算符載操做

在講解重載運算符前須要先說明Dart裏面的一個關鍵字operator,operator和運算符一塊兒使用,表示一個運算符重載函數,在理解時能夠將operator和運算符(如operator+或operator-)視爲一個函數名。編寫一個例子方便理解。

Class Vector {
    final int x;
    final int y;
    const Vector(this.x,this.y);

    //重載加號 + (a+b)
    Vector operator + (Vector v){
        return new Vector(x + v.x,y + v.y);
    }
}

void main() {
    //實例化兩個變量
    final result1 = new Vector(10,20);
    final result2 = new Vector(30,40);

    final result = result1 + result2;

    print('result.x = '+result.x.toString()+'',+'result.y = '+result.y.toString());

    //打印結果
    result.x = 40,result.y = 60
}

首先建立了一個Vector類,聲明兩個成員變量x和y還有一個構造方法,在Vector類裏面重載一個加法運算符,重載操做返回Vector對象,接下來在main函數裏面,實例化了兩個Vector變量,兩次操做分別給

x和y進行了賦值,x = 10;y = 20;x = 30;y = 40。而後讓result1和result2這兩個變量相加,看到這裏你們可能會有疑問,兩個對象變量怎麼相加呢?這裏咱們的運算符重載就發揮出做用了,實際上,在執行final result = result1 + result2;這行代碼的時候,實際上是對象result1調用了"operator +"這個函數,並將result2這個對象看成一個參數傳遞給了這個函數,從而實現了對象result1中的x和對象result2中的x相加,對象result1中的y和對象result2中的y相加的操做,因此最終打印的結果result.x = 40,result.y = 60。

注:對於 Dart 提供的全部操做符,一般只支持對於基本數據類型和標準庫中提供的類的操做,而對於用戶本身定義的類,若是想要經過該操做符實現一些基本操做(好比比較大小,判斷是否相等),就須要用戶本身來定義關於這個操做符的具體實現了。

  •  繼承類

繼承是面向對象編程技術的一塊基石,由於它容許建立分等級層次的類。繼承就是子類繼承父類的特徵和行爲,使得子類對象具備父類的實例域和方法;或子類從父類繼承方法,使得子類具備父類相同的行爲。Dart裏面使用extends關鍵字來實現繼承,super關鍵字來指定父類。

Class Animal {
    void eat(){
        print('動物會吃');
    }

    void run(){
        print('動物會跑');
    }
}

Class Human extends Animal {
    void say(){
        print('人會說');
    }

    void study(){
        print('人會學習');
    }
}

void main(){
    var animal = new Animal();
    animal.eat();
    animal.run();

    value human = new Human();
    human.eat();
    human.run();
    human.say();
    human.study();

    //打印結果
    動物會吃
    動物會跑

    動物會吃
    動物會跑
    人會說
    人會學習
}

 

  • 抽象類

抽象類相似於Java語言中的接口。抽象類裏不具體實現方法,只是寫好定義接口,具體實現留着調用的人去實現。抽象類可使用abstract關鍵字定義類。

  1. 抽象類經過abstract關鍵字來定義。
  2. Dart中的抽象方法不能用abstract聲明,Dart中沒有方法體的方法咱們成爲抽象方法。
  3. 若是子類繼承了抽象類,就必須實現裏面的抽象方法。
  4. 若是把抽象類看成接口實現的話,就必須得實現抽象類裏面的全部屬性和方法。
  5. 抽象類不能實例化,只有繼承它的子類能夠實例化。
abstract class Animal{
    eat();   //抽象方法
    run();  //抽象方法  
    printInfo(){
    print('我是一個抽象類裏面的普通方法');
  }
}

class Dog extends Animal{
    @override
    eat() {
        print('小狗在吃骨頭');
    }

    @override
    run() {
        // TODO: implement run
        print('小狗在跑');
    }  
}
class Cat extends Animal{
    @override
    eat() {
        // TODO: implement eat
        print('小貓在吃老鼠');
    }

    @override
    run() {
        // TODO: implement run
        print('小貓在跑');
    }

}

void main(){
    Dog d=new Dog();
    d.eat();
    d.printInfo();

    Cat c=new Cat();
    c.eat();
    c.printInfo();

    // Animal a=new Animal();   //抽象類無法直接被實例化
}

 

Dart學習系列文章:https://www.cnblogs.com/jukaiit/category/1636484.html
相關文章
相關標籤/搜索