參考:https://www.dartcn.com/guides/language/language-tour#%E7%B1%BB
類
Dart
是一種基於類和 mixin
繼承機制的面向對象的語言。 每個對象都是一個類的實例,所有的類都繼承於 Object
。
基於 Mixin 繼承 意味着每個類(除 Object
外) 都只有一個超類, 一個類中的代碼可以在其他多個繼承類中重複使用。
使用類的成員變量
對象的由函數和數據(即方法和實例變量)組成。 方法的調用要通過對象來完成: 調用的方法可以訪問其對象的其他函數和數據。
使用 (.) 來引用實例對象的變量和方法:
var p = Point(2, 2);
// 爲實例的變量 y 設置值。
p.y = 3;
使用 ?. 來代替 . , 可以避免因爲左邊對象可能爲 null , 導致的異常:
var p = Point(2, 2);
// 如果 p 爲 non-null,設置它變量 y 的值爲 4。
p?.y = 4;
使用構造函數
通過 構造函數 創建對象。 構造函數的名字可以是 ClassName
或者 ClassName.identifier
。例如, 以下代碼使用 Point
和 Point.fromJson()
構造函數創建 Point
對象:
var p1 = Point(2, 2);
var p2 = Point.fromJson({'x': 1, 'y': 2});
獲取對象的類型
使用對象的runtimeType
屬性, 可以在運行時獲取對象的類型, runtimeType
屬性回返回一個 Type
對象。
print('The type of a is ${a.runtimeType}');
構造函數
通過創建一個與其類同名的函數來聲明構造函數
class Point {
num x, y;
Point(num x, num y) {
this.x = x;
this.y = y;
}
}
通常模式下,會將構造函數傳入的參數的值賦值給對應的實例變量, Dart
自身的語法糖精簡了這些代碼:
class Point {
num x, y;
// 在構造函數體執行前,
// 語法糖已經設置了變量 x 和 y。
Point(this.x, this.y);
}
在沒有聲明構造函數的情況下,
Dart
會提供一個默認的構造函數。 默認構造函數沒有參數並會調用父類的無參構造函數。
子類不會繼承父類的構造函數。 子類不聲明構造函數,那麼它就只有默認構造函數 (匿名,沒有參數) 。
重定向構造函數
有時構造函數的唯一目的是重定向到同一個類中的另一個構造函數。 重定向構造函數的函數體爲空, 構造函數的調用在冒號(:)
之後。(類似於Android
中自定義 View需要實現多個構造函數時調用最終的構造函數)
class Point {
num x, y;
// 類的主構造函數。
Point(this.x, this.y);
// 指向主構造函數
Point.alongXAxis(num x) : this(x, 0);
}
工廠構造函數
當執行構造函數並不總是創建這個類的一個新實例時,則使用 factory
關鍵字。 例如,一個工廠構造函數可能會返回一個 cache
中的實例, 或者可能返回一個子類的實例。
(類似於Android
中單例模式)
以下示例演示了從緩存中返回對象的工廠構造函數:
class Logger {
final String name;
bool mute = false;
// 從命名的 _ 可以知,
// _cache 是私有屬性。
static final Map<String, Logger> _cache =
<String, Logger>{};
factory Logger(String name) {
if (_cache.containsKey(name)) {
return _cache[name];
} else {
final logger = Logger._internal(name);
_cache[name] = logger;
return logger;
}
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
提示: 工廠構造函數無法訪問 this。
工廠構造函的調用方式與其他構造函數一樣:
var logger = Logger('UI');
logger.log('Button clicked');
方法
方法是爲對象提供行爲的函數。
實例方法
對象的實例方法可以訪問 this 和實例變量。 以下示例中的 distanceTo() 方法就是實例方法:
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);
}
}
抽象方法
只定義接口不進行實現,而是留給其他類去實現。 抽象方法只存在於 抽象類 中。
定義一個抽象函數,使用分號(;)
來代替函數體:
abstract class Doer {
// 定義實例變量和方法 ...
void doSomething(); // 定義一個抽象方法。
}
class EffectiveDoer extends Doer {
@override
void doSomething() {
print("123");
// 提供方法實現,所以這裏的方法就不是抽象方法了...
}
}
void main() {
var eff = EffectiveDoer();
eff.doSomething();
}
輸出:
123
枚舉類型
枚舉類型也稱爲enumerations 或 enums
, 是一種特殊的類,用於表示數量固定的常量值。
使用 enum
關鍵字定義一個枚舉類型:
enum Color { red, green, blue }
枚舉中的每個值都有一個index getter
方法, 該方法返回值所在枚舉類型定義中的位置(從 0 開始)。
例如,第一個枚舉值的索引是 0 , 第二個枚舉值的索引是 1。
assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);
使用枚舉的values
常量, 獲取所有枚舉值列表(list
)。
List<Color> colors = Color.values;
assert(colors[2] == Color.blue);
爲類添加功能: Mixin
Mixin
是複用類代碼的一種途徑, 複用的類可以在不同層級,之間可以不存在繼承關係。
通過創建一個繼承自 Object
且沒有構造函數的類,來 實現 一個Mixin
。 如果 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');
}
}
}
通過 with
後面跟一個或多個混入的名稱,來 使用 Mixin
, 下面的示例演示了兩個使用 Mixin
的類:
class Musician extends Performer with Musical {
// ···
}
class Maestro extends Person
with Musical, Aggressive, Demented {
Maestro(String maestroName) {
name = maestroName;
// Musical 類中的變量
canConduct = true;
}
}
指定只有某些類型可以使用的 Mixin -
比如, Mixin
可以調用 Mixin
自身沒有定義的方法 - 使用 on
來指定可以使用Mixin
的父類類型:
mixin MusicalPerformer on Musician {
// ···
}
mixin
詳解可查看 Dart之Mixin詳解
類變量和方法
使用 static 關鍵字實現類範圍的變量和方法。
靜態變量
Dart
中靜態變量只到它們被使用的時候纔會初始化。
而Java
中靜態變量是隨着類的加載而加載的,所以當類加載進內存的時候,靜態變量就已經伴隨着類的加載而初始化進內存了,並且靜態變量只在類加載時加載一次,存放在方法區中的靜態區中。
class Queue {
static const initialCapacity = 16;
// ···
}
void main() {
assert(Queue.initialCapacity == 16);
}
靜態方法
靜態方法(類方法)不能在實例上使用,因此它們不能訪問 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);
}
輸出:
2.8284271247461903