方法是爲對象提供行爲的函數。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);
}
}
複製代碼
Gettter 和 Setters 是爲了可以讀寫對象屬性的指定方法。回想一下,每一個實例變量都有一個隱式getter,還有可能有一個setter。 你可使用get
和set
關鍵字經過實現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()
:
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 }
複製代碼
枚舉中的每一個值都有一個index
getter,它返回枚舉值的索引位置。 例如,第一個值具備索引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'
}
複製代碼
枚舉類型具備如下限制:
混合是一種在多個類層次結構中重用類代碼的方法。
使用混合的方法是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
關鍵字實現類範圍的變量和方法。
靜態變量(類變量)一般用做類範圍的狀態和常量:
class Queue {
static const initialCapacity = 16;
// ···
}
void main() {
assert(Queue.initialCapacity == 16);
}
複製代碼
靜態變量在使用以前不會初始化。
注意:優先選擇
lowerCamelCase
做爲常量名稱。
靜態方法(類方法)不對實例進行操做,所以沒法使用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)函數而不是靜態方法。
你可使用靜態方法做爲編譯時常量。 例如,能夠將靜態方法做爲參數傳遞給常量構造函數。