Dart基礎之Classes(類)下篇

方法(Method)

方法是爲對象提供行爲的函數。java

實例方法

實例方法能夠訪問實例變量和this。下面的distanceTo()就是一個實例方法的例子:git

import 'dart:math';

class Point {
  num x, y;

  Point(this.x, this.y);

  num distanceTo(Point other) {
    var dx = x - other.x;
    var dy = y - other.y;
    return sqrt(dx * dx + dy * dy);
  }
}
複製代碼

Getters 和 Setters

Gettter 和 Setters 是爲了可以讀寫對象屬性的指定方法。回想一下,每一個實例變量都有一個隱式getter,還有可能有一個setter。 你可使用getset關鍵字經過實現getter和setter來建立其餘屬性:github

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

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

  // 定義兩個計算的屬性: right 和 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;
}

void main() {
  var rect = Rectangle(3, 4, 20, 15);
  assert(rect.left == 3);
  rect.right = 12;
  assert(rect.left == -8);
}
複製代碼

使用getter和setter,你能夠從實例變量開始,稍後使用方法包裝它們,而無需更改客戶端代碼。安全

注意:不管是否明肯定義了getter,增量(++)等運算符都以預期的方式工做。 爲避免任何意外的反作用,運算符只需調用一次getter,將其值保存在臨時變量中。ide

抽象方法

實例,getter和setter方法能夠是抽象的,定義一個接口,但將其實現留給其餘類。 抽象方法只能存在於抽象類中。(這個跟 java 裏是同樣的)函數

要使方法成爲抽象,請使用分號(;)而不是方法體{}:post

abstract class Doer {
  // 定義實例變量和方法...

  void doSomething(); // 定義一個抽象方法.
}

class EffectiveDoer extends Doer {
  void doSomething() {
    // 提供一個實現,因此這裏的方法不是抽象的...
  }
}
複製代碼

抽象類

使用abstract修飾符定義抽象類 - 沒法實例化的類。 抽象類對於定義接口很是有用,一般還有一些實現。 若是但願抽象類看起來是可實例化的,請定義工廠構造函數。ui

抽象類一般有抽象方法。 下面是一個聲明具備抽象方法的抽象類:this

// 這個類定義了 abstract 不能被實例化
abstract class AbstractContainer {
  // 定義構造函數,字段,方法...

  void updateChildren(); // 抽象方法.
}
複製代碼

隱式接口

每一個類都隱式定義一個接口,該接口包含該類的全部實例成員及其實現的任何接口。 若是要在不繼承B實現的狀況下建立支持B類API的A類,則A類應實現B接口。spa

類經過在implements子句中聲明它們而後提供接口所需的API來實現一個或多個接口。 例如:

// A person. 隱式接口包含了 greet().
class Person {
  // 在接口中, 但只有在這個庫中可見
  final _name;

  // 不在接口中, 由於這是一個構造函數
  Person(this._name);

  // 在接口中
  String greet(String who) => 'Hello, $who. I am $_name.';
}

// 一個Person 接口的實現
class Impostor implements Person {
  get _name => '';

  String greet(String who) => 'Hi $who. Do you know who I am?';
}

String greetBob(Person person) => person.greet('Bob');

void main() {
  print(greetBob(Person('Kathy')));
  print(greetBob(Impostor()));
}
複製代碼

這是一個指定類實現多個接口的示例:

class Point implements Comparable, Location {...}
複製代碼

繼承一個類

extends去建立一個子類,用super去指向一個超類

class Television {
  void turnOn() {
    _illuminateDisplay();
    _activateIrSensor();
  }
  // ···
}

class SmartTelevision extends Television {
  void turnOn() {
    super.turnOn();
    _bootNetworkInterface();
    _initializeMemory();
    _upgradeApps();
  }
  // ···
}
複製代碼

重載成員

子類能夠覆蓋實例方法,getter和setter。 你可使用@override註釋來覆蓋成員:

class SmartTelevision extends Television {
  @override
  void turnOn() {...}
  // ···
}
複製代碼

要在類型安全的代碼中縮小方法參數或實例變量的類型,可使用covariant關鍵字

可覆蓋的運算符

你能夠覆蓋下表中展現的運算符。 例如,若是定義Vector類,則能夠定義一個+方法來添加兩個向量。

< + | []
> / ^ []=
<= ~/ & ~
>= * << ==
- % >>

注意:你可能已經注意到 != 不是可覆蓋的運算符。 表達式e1!= e2只是!(e1==e2)的語法糖。

這是一個覆蓋+-運算符的類示例:

class Vector {
  final int x, y;

  Vector(this.x, this.y);

  Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
  Vector operator -(Vector v) => Vector(x - v.x, y - v.y);
}

void main() {
  final v = Vector(2, 3);
  final w = Vector(2, 2);

  assert(v + w == Vector(4, 5));
  assert(v - w == Vector(0, 1));
}
複製代碼

若是覆蓋==,則還應該覆蓋Object的hashCode getter。(相似 java 中的覆寫 equals(),還有 hashcode()) 有關重寫==hashCode的示例,請參閱實現映射鍵

noSuchMethod()

要在代碼嘗試使用不存在的方法或實例變量時檢測或作出反應,你能夠覆蓋noSuchMethod()

class A {
  // 除非你覆蓋了 noSuchMethod,
  // 用一個不存在的成員會致使 NoSuchMethodError 結果.
  @override
  void noSuchMethod(Invocation invocation) {
    print('You tried to use a non-existent member: ' +
        '${invocation.memberName}');
  }
}
複製代碼

除非知足如下條件之一,不然不能調用未實現的方法:

  • 接收器具備靜態類型dynamic

  • 接收器有一個定義未實現方法的靜態類型(抽象是ok的),接收器的動態類型有一個noSuchMethod()實現,它與Object類中的實現不一樣。

有關更多信息,請參閱非正式noSuchMethod轉發規範

枚舉類型

枚舉類型(一般稱爲枚舉或枚舉)是一種特殊類,用於表示固定數量的常量值。

使用枚舉

enum申明一個枚舉類型

enum Color { red, green, blue }
複製代碼

枚舉中的每一個值都有一個indexgetter,它返回枚舉值的索引位置。 例如,第一個值具備索引0,第二個值具備索引1。

assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);
複製代碼

要獲取枚舉中全部值的列表,用枚舉.values獲取枚舉的常量列表。

List<Color> colors = Color.values;
assert(colors[2] == Color.blue);
複製代碼

你能夠在switch語句中使用枚舉,若是不處理全部枚舉值,將收到警告:

var aColor = Color.blue;

switch (aColor) {
  case Color.red:
    print('Red as roses!');
    break;
  case Color.green:
    print('Green as grass!');
    break;
  default: // 不寫這個 default,你會看到WARNING.
    print(aColor); // 'Color.blue'
}
複製代碼

枚舉類型具備如下限制:

  • 不能子類化,混合或實現枚舉。
  • 沒法顯式實例化枚舉。

向類添加功能:mixins(混合)

混合是一種在多個類層次結構中重用類代碼的方法。

使用混合的方法是with關鍵字後跟一個或多個mixin命名的類。 如下示例顯示了兩個使用mixins的類:

class Musician extends Performer with Musical {
  // ···
}

class Maestro extends Person with Musical, Aggressive, Demented {
  Maestro(String maestroName) {
    name = maestroName;
    canConduct = true;
  }
}
複製代碼

要定義一個mixin,首先建立一個mixin開頭的Object擴展類,而且不能聲明構造函數。 除非你但願mixin可用做常規類,不然請使用mixin關鍵字而不是class。 例如:

mixin Musical {
  bool canPlayPiano = false;
  bool canCompose = false;
  bool canConduct = false;

  void entertainMe() {
    if (canPlayPiano) {
      print('Playing piano');
    } else if (canConduct) {
      print('Waving hands');
    } else {
      print('Humming to self');
    }
  }
}
複製代碼

要指定只有某些類型可使用mixin - 例如,mixin能夠調用它沒有定義的方法 - 使用on來指定所需的超類:

mixin MusicalPerformer on Musician {
  // ···
}
複製代碼

版本說明:Dart 2.1中引入了對mixin關鍵字的支持。 早期版本中的代碼一般使用抽象類。 有關2.1 mixin更改的更多信息,請參閱Dart SDK changelog和2.1 mixin規範。

類變量和方法

使用static關鍵字實現類範圍的變量和方法。

Static 變量

靜態變量(類變量)一般用做類範圍的狀態和常量:

class Queue {
  static const initialCapacity = 16;
  // ···
}

void main() {
  assert(Queue.initialCapacity == 16);
}
複製代碼

靜態變量在使用以前不會初始化。

注意:優先選擇lowerCamelCase做爲常量名稱。

Static 方法

靜態方法(類方法)不對實例進行操做,所以沒法使用this關鍵字。 例如:

import 'dart:math';

class Point {
  num x, y;
  Point(this.x, this.y);

  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 main() {
  var a = Point(2, 2);
  var b = Point(4, 4);
  var distance = Point.distanceBetween(a, b);
  assert(2.8 < distance && distance < 2.9);
  print(distance);
}
複製代碼

注意:對於經常使用或普遍使用的實用程序和功能,請考慮使用頂級(top-level)函數而不是靜態方法。

你可使用靜態方法做爲編譯時常量。 例如,能夠將靜態方法做爲參數傳遞給常量構造函數。

相關文章
相關標籤/搜索