Dart 基礎(chǔ)(四)

級(jí)別: ★☆☆☆☆
標(biāo)簽:「Flutter 」「Dart」「Dart class」「Dart mixin」「Dart override」
作者: WYW
審校: QiShare團(tuán)隊(duì)


前言:
4篇Dart基礎(chǔ)已經(jīng)全部更新完成。目錄如下:
Dart 基礎(chǔ) (一)
Dart 基礎(chǔ) (二)
Dart 基礎(chǔ) (三)
Dart 基礎(chǔ) (四)

筆者在本文中主要會(huì)分享:類(lèi)、實(shí)例變量、構(gòu)造方法、命名構(gòu)造方法、實(shí)例方法、靜態(tài)變量、靜態(tài)方法、set、get 方法、extendsimplementsmixinabstractoverride相關(guān)的內(nèi)容。

1.類(lèi)

下邊筆者先以Point 類(lèi)為例,分享下關(guān)于實(shí)例變量構(gòu)造方法命名構(gòu)造方法實(shí)例方法靜態(tài)方法靜態(tài)變量set get方法 的內(nèi)容。

Dart 是一種面向?qū)ο蟮木幊陶Z(yǔ)言,同時(shí)支持基于 mixin 的繼承機(jī)制。mixin相關(guān)的內(nèi)容會(huì)在下文解釋。每個(gè)對(duì)象都是一個(gè)類(lèi)的實(shí)例,所有的類(lèi)都繼承于 Object。 基于 Mixin 的繼承 意味著每個(gè)類(lèi)(Object 除外) 都只有一個(gè)超類(lèi),一個(gè)類(lèi)的代碼可以在其他 多個(gè)類(lèi)繼承中重復(fù)使用。

使用 new 關(guān)鍵字和構(gòu)造方法來(lái)創(chuàng)建新的對(duì)象。 構(gòu)造方法名字可以為 ClassName 或者 ClassName.identifier。
在Dart2.0的時(shí)候,創(chuàng)建新的對(duì)象的時(shí)候,new 關(guān)鍵字是可選的。當(dāng)前Dart最新版本是2.4.0,2019-06-27 Dart開(kāi)發(fā)團(tuán)隊(duì)發(fā)布2.4.0版本Dart。 Dart change log

1.1 實(shí)例變量

class Point {
  
  // 實(shí)例變量
  num x;
  num y;
}

1.2 構(gòu)造方法:構(gòu)造方法 定義一個(gè)和類(lèi)名一樣的方法

 // 構(gòu)造方法 定義一個(gè)和類(lèi)名一樣的方法
  Point(num x, num y) {
    // this 關(guān)鍵字指當(dāng)前的實(shí)例
    this.x = x;
    this.y = y;
  }
  
  // 由于把構(gòu)造方法參數(shù)賦值給實(shí)例變量的場(chǎng)景太常見(jiàn)了, Dart 提供了一個(gè)語(yǔ)法糖來(lái)簡(jiǎn)化這個(gè)操作
  // Point(this.x, this.y);

1.3 命名構(gòu)造方法

 // 命名構(gòu)造方法
  Point.fromJson(Map json) {
    // 只有當(dāng)名字沖突的時(shí)候才使用 this。否則的話(huà), Dart 代碼風(fēng)格樣式推薦忽略 this。
    x = json['x'];
    y = json['y'];
  }

  Point.namedConstructor(Map json){
    x = json['x'];
    y = json['y'];
  }

命名構(gòu)造方法使用場(chǎng)景有:模型類(lèi)中解析數(shù)據(jù)場(chǎng)景。

舉個(gè)簡(jiǎn)單例子:如返回一個(gè)列表數(shù)據(jù)的情況,返回?cái)?shù)據(jù)可能是是一個(gè)包著多個(gè)字典的數(shù)組,那么,處理相應(yīng)數(shù)據(jù)的時(shí)候,需要對(duì)數(shù)據(jù)進(jìn)行相應(yīng)的解析。解析的過(guò)程就可能用到命名構(gòu)造方法。把一個(gè)個(gè)字典當(dāng)做實(shí)例,提取出來(lái)。

[
    {
        "name":"QiShare1",
        "age":"1"
    },
    {
        "name":"QiShare2",
        "age":"1"
    },
    {
        "name":"QiShare3",
        "age":"1"
    },
    {
        "name":"QiShare4",
        "age":"1"
    },
    {
        "name":"QiShare5",
        "age":"1"
    },
    {
        "name":"QiShare6",
        "age":"1"
    },
    {
        "name":"QiShare7",
        "age":"1"
    },
]

1.4 實(shí)例方法

// 實(shí)例方法
  num distanceTo(Point other) {
    var dx = x - other.x;
    var dy = y - other.y;
    return sqrt(dx*dx + dy*dy);
  }

1.5 靜態(tài)方法

使用static關(guān)鍵字修飾的方法為靜態(tài)方法,相當(dāng)于類(lèi)方法。使用類(lèi)名可以直接調(diào)用。

// 靜態(tài)方法
  static num distanceBetween(Point a, Point b) {
    var dx = a.x - b.x;
    var dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
  }
void classDemo() {

    var jsonData = jsonDecode('{"x":2, "y":2}');
    // Create a Point using Point().
    var p1 = new Point(1, 1);
    print('p1點(diǎn)x坐標(biāo):${p1.x}');
    print('p1點(diǎn)y坐標(biāo):${p1.y}');

    // Create a Point using Point.fromJson().
    var p2 = new Point.fromJson(jsonData);
    print('p2點(diǎn)x坐標(biāo):${p2.x}');
    print('p2點(diǎn)y坐標(biāo):${p2.y}');

    num distance = p2.distanceTo(p1);
    print('p1到p2的距離: $distance');

    Map jsonData3 = {
      'x': 3,
      'y': 3,
    };

    Point p3 = Point.namedConstructor(jsonData3);
    print('p3點(diǎn)x坐標(biāo):${p3.x}');
    print('p3點(diǎn)y坐標(biāo):${p3.y}');
    
    num distance12 = Point.distanceBetween(p1, p2);
    print('p1和p2之間的距離 $distance12');
    
    }
    

輸出內(nèi)容

flutter: p1點(diǎn)x坐標(biāo):1
flutter: p1點(diǎn)y坐標(biāo):1
flutter: p2點(diǎn)x坐標(biāo):2
flutter: p2點(diǎn)y坐標(biāo):2
flutter: p1到p2的距離: 1.4142135623730951
flutter: p3點(diǎn)x坐標(biāo):3
flutter: p3點(diǎn)y坐標(biāo):3
flutter: p1和p2之間的距離 1.4142135623730951

1.6 靜態(tài)變量

靜態(tài)變量對(duì)于類(lèi)級(jí)別的狀態(tài)是非常有用的,筆者對(duì)這句話(huà)的理解是:靜態(tài)變量可以由類(lèi)名直接調(diào)用。

class Color {
  static const red =
      const Color('red'); // A constant static variable.
  final String name;      // An instance variable.
  const Color(this.name); // A constant constructor.
}

使用方式

    String colorName = Color.red.name;
    print('colorName:$colorName');

輸出內(nèi)容

colorName:red`

1.7 set get 方法

下邊筆者舉了一個(gè)類(lèi)Rectangle的left、top、width、height的Set、Get方法的例子。

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

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

  // Define two calculated properties: right and bottom.
  num get right             => left + width;
      set right(num value)  => left = value - width;
  num get bottom            => top + height;
      set bottom(num value) => top = value - height;
}

使用方式

Rectangle rectangel = Rectangle(0, 0, 375, 667);
    print('rectangel.left:');
    print(rectangel.left);
    print('rectangel.right:');
    print(rectangel.right);
    print('rectangel.width:');
    print(rectangel.width);
    print('rectangel.height:');
    print(rectangel.height);
    print('rectangel.right:');
    print(rectangel.right);
    print('rectangel.bottom:');
    print(rectangel.bottom);

輸出結(jié)果:

flutter: rectangel.left:
flutter: 0
flutter: rectangel.right:
flutter: 375
flutter: rectangel.width:
flutter: 375
flutter: rectangel.height:
flutter: 667
flutter: rectangel.right:
flutter: 375
flutter: rectangel.bottom:
flutter: 667

2. extends 與 implements

extends

關(guān)鍵字extends 用于繼承父類(lèi)的實(shí)例變量及方法等。Dart 只支持單繼承。

implements

Every class implicitly defines an interface containing all the instance members of the class and of any interfaces it implements. If you want to create a class A that supports class B’s API without inheriting B’s implementation, class A should implement the B interface.

每個(gè)類(lèi)都隱式地聲明了一個(gè)包含所有的實(shí)例變量和類(lèi)已經(jīng)實(shí)現(xiàn)的接口。
如果你想創(chuàng)建一個(gè)類(lèi)A,沒(méi)有繼承類(lèi)B,但是類(lèi)A可訪問(wèn)類(lèi)B的API,那么類(lèi)A 應(yīng)該實(shí)現(xiàn)類(lèi)B的接口。
上邊的內(nèi)容,結(jié)合著下邊的例子,筆者的理解是:Chicken隱式地聲明了Animal 的實(shí)例變量,和類(lèi)Animal 已經(jīng)實(shí)現(xiàn)的方法。Chicken支持在沒(méi)有繼承類(lèi)Animal的情況下,可訪問(wèn)類(lèi)B的API。
一個(gè)類(lèi)可以implements 多個(gè)類(lèi)的API,所以implements算是一種變向?qū)崿F(xiàn)多繼承的方式。


class Animal {
  String name;
  void ability() {
    print('Animal 的能力');
  }
}

class Bird extends Animal {
  void ability(){
    print('bird can fly');
  }
}

class Fish extends Animal {
  void ability(){
    print('fish can swim');
  }
}

class Dog extends Animal {
  void ability(){
    print('dog can bark');
  }
}

class Chicken implements Animal {
  String name;
  void ability() {
    print('chicken can lay eggs');
  }
}

調(diào)用如上代碼的方式及相應(yīng)輸出結(jié)果如下:

    Dog dog = Dog();
    dog.ability();
    Fish fish = Fish();
    fish.ability();
    Bird bird = Bird();
    bird.ability();
    Chicken chicken = Chicken();
    chicken.ability();
    
    

// 輸出結(jié)果:
flutter: dog can bark
flutter: fish can swim
flutter: bird can fly
flutter: chicken can lay eggs

3. mixin

Mixins 是一種在多類(lèi)繼承中重用一個(gè)類(lèi)代碼的方法。筆者的理解是,mixin相當(dāng)于是一個(gè)工具類(lèi),使用 with 關(guān)鍵字使用了mixin的類(lèi),就可以使用mixin中的代碼。

Mixins are a way of reusing a class’s code in multiple class hierarchies.

To use a mixin, use the with keyword followed by one or more mixin names. The following example shows two classes that use mixins:

Mixin 是一種在多個(gè)類(lèi)中重用某些代碼的方式。
使用mixin ,需使用 with 關(guān)鍵字,with后邊跟mixin的名,with 后邊可以跟多個(gè)mixin名字,及可以同時(shí)使用多個(gè)mixin中的代碼。下邊筆者舉了一個(gè)開(kāi)發(fā)者學(xué)習(xí)基礎(chǔ)語(yǔ)言的例子。

筆者定義了一個(gè)Developer的mixin,如果是iOS 開(kāi)發(fā)者需要先學(xué)習(xí)C語(yǔ)言基礎(chǔ),如果是Android 開(kāi)發(fā)者,需要先學(xué)習(xí)Java語(yǔ)言,如果是Flutter 開(kāi)發(fā)者,需要先學(xué)習(xí)Dart 語(yǔ)言。

mixin Developer {
    bool isIOS = false;
    bool isAndroid = false;
    bool isFlutter = false;
    
    // 需要學(xué)習(xí)的基礎(chǔ)語(yǔ)言
    void needLearnBaseProgram () {
      if (isIOS) {
        print('Need Learn C Firstly');
      } else if (isAndroid) {
        print('Need Learn Java Firstly');
      } else if (isFlutter) {
        print('Need Learn Dart Firstly');
      } else {
        print('May be need Learn Other Language');
      }
    }
    
  }

class FlutterDeveloper with Developer {
    String name;
    FlutterDeveloper(String name) {
        isFlutter = true;
        this.name = name;
    }
}
  

使用的相關(guān)代碼:

    FlutterDeveloper flutterDeveloper = FlutterDeveloper('FlutterEnginerName');
    flutterDeveloper.needLearnBaseProgram();
    
    // 輸出結(jié)果: flutter: Need Learn Dart Firstly

注意事項(xiàng): 當(dāng)在if else 場(chǎng)景下使用 bool 類(lèi)型變量的時(shí)候,需要注意bool變量是否賦值過(guò)了,否則會(huì)有類(lèi)似如下的異常信息。

flutter: The following assertion was thrown while handling a gesture:
flutter: Failed assertion: boolean expression must not be null

4. abstract

使用 abstract 修飾的類(lèi) 記為抽象類(lèi)。抽象類(lèi)用于定義接口 及部分實(shí)現(xiàn)。

筆者舉了如下例子:

創(chuàng)建了People 類(lèi),并且聲明了 String skinColor();的抽象方法,創(chuàng)建并實(shí)現(xiàn)了 void ability() 方法;

abstract class People {
  String skinColor();
  void ability() {
    print('All can Communicate');
  }

}

class YellowPeople extends People {
  @override
  String skinColor() {
    String color = 'Yellow';
    print(color);
    return color;
  }
}

class BlackPeople extends People {
  @override
    skinColor() {
      String color = 'black';
      print(color);
      return color;
    }
}

class WhitePeople extends People {
@override
  skinColor() {
    String color = 'White';
    print(color);
    return color;
  }
}

下邊是使用示例,及相應(yīng)的輸出結(jié)果。


YellowPeople yellowPeople = YellowPeople();
yellowPeople.ability();
yellowPeople.skinColor();

WhitePeople whitePeople = WhitePeople();
whitePeople.ability();
whitePeople.skinColor();

BlackPeople blackPeople = BlackPeople();
blackPeople.ability();
blackPeople.skinColor();
    
// 輸出結(jié)果:
flutter: All can Communicate
flutter: Yellow
flutter: All can Communicate
flutter: White
flutter: All can Communicate
flutter: black

  • 抽象類(lèi)不能創(chuàng)建實(shí)例。
  • 抽象方法為沒(méi)有方法體的方法。只有抽象類(lèi)中可以寫(xiě)抽象方法,其他普通類(lèi)不可以。
    • 例:如果BlackPeople的skinColor 沒(méi)有方法體即沒(méi)有實(shí)現(xiàn),則會(huì)報(bào)錯(cuò)如下:'skinColor' must have a method body because 'BlackPeople' isn't abstract.
      Try making 'BlackPeople' abstract, or adding a body to 'skinColor'.
  • 繼承了抽象類(lèi)的子類(lèi)必須實(shí)現(xiàn)抽象方法
    • 以WhitePeople 為例,如果不實(shí)現(xiàn)skinColor 方法會(huì)報(bào)出如下錯(cuò)誤:
      • Missing concrete implementation of People.skinColor.
      • Try implementing the missing method, or make the class abstract.

5. override

"5.1 override 運(yùn)算符"及override toString

這里筆者對(duì)override 運(yùn)算符添加了引號(hào)。至于原因,等大家看完了下邊的內(nèi)容之后,便會(huì)了解筆者的用意。下文提到的override和重寫(xiě)是一個(gè)意思。

先看下運(yùn)算符重寫(xiě)的示例代碼:

Vector 類(lèi),重寫(xiě)了+ 運(yùn)算符和減運(yùn)算符,以達(dá)到Vector可以直接進(jìn)行加減的目的。筆者還重寫(xiě)了Vector類(lèi)的toString 方法,便于查看Vector的x、y值。

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

  Vector operator +(Vector v) {
    return Vector(x + v.x, y + v.y);
  }

  Vector operator -(Vector v) {
    return Vector(x - v.x, y - v.y);
  }
  
  @override
  String toString() {
    return 'runtimeType:' + this.runtimeType.toString() + ',x:' + x.toString() +',y:' + y.toString();
  }
  
}

使用Vector的+、-運(yùn)算符,及重寫(xiě)toString后,使用Vector的示例代碼及輸出結(jié)果如下:

    Vector v1 = Vector(1, 1);
    Vector v2 = Vector(2, 2);
    Vector v3 = v1 + v2;
    Vector v0 = v2 - v1;
    print(v0);
    print(v3);

// 輸出結(jié)果: 
flutter: runtimeType:Vector,x:1,y:1
flutter: runtimeType:Vector,x:3,y:3

重寫(xiě)toString的效果是:可控制print的對(duì)象的內(nèi)容及格式。這一點(diǎn)便于非調(diào)試環(huán)境下查看一些具體錯(cuò)誤信息。

上文筆者提到了重寫(xiě)運(yùn)算符是加引號(hào)的原因如下:在筆者看來(lái),運(yùn)算符的重寫(xiě)有點(diǎn)跑題了。重寫(xiě)toString才算是重寫(xiě)。重寫(xiě)的toString的返回值、方法名和參數(shù)和父類(lèi)Object都一樣。如大家有不同理解,歡迎討論。

參考學(xué)習(xí)網(wǎng)址


推薦文章:
Dart基礎(chǔ)(一)
Dart基礎(chǔ)(二)
Dart基礎(chǔ)(三)
iOS 短信驗(yàn)證碼倒計(jì)時(shí)按鈕
iOS 環(huán)境變量配置
iOS 中處理定時(shí)任務(wù)的常用方法
算法小專(zhuān)欄:貪心算法
iOS 快速實(shí)現(xiàn)分頁(yè)界面的搭建
iOS 中的界面旋轉(zhuǎn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,797評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,179評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 175,628評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,642評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,444評(píng)論 6 405
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 54,948評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,040評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,185評(píng)論 0 287
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,717評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,602評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,794評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,045評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,418評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,671評(píng)論 1 281
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,414評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,750評(píng)論 2 370

推薦閱讀更多精彩內(nèi)容