Dart 只能單繼承参淫,但是可以多層繼承制市。
調(diào)用成員變量
操作符幾乎和別的語言類似示损,提個比較特殊的賦值操作符 ??= 和 ?.操作符:
var a = 1;
var b;
b ?? = a; // 如果 b 的值是 null 則將 a 賦值給 b朗和,否則保持不變
var c = size?.x; // 如果 size 為 null 則返回 null馁痴,否則返回 size.a 的值
構(gòu)造函數(shù)
使用
通過 構(gòu)造函數(shù) 創(chuàng)建對象谊娇。 構(gòu)造函數(shù)的名字可以是 *ClassName*
或者 *ClassName*.*identifier*
。例如罗晕, 以下代碼使用 a 和 a.instance()
構(gòu)造函數(shù)創(chuàng)建 Point
對象:
var a1 = a(2, 2);
var a2 = a.instance({'x': 1, 'y': 2});
//在 Dart 2 中 new 關(guān)鍵字變成了可選的济欢。
var a1 = new a(2, 2);
var a2 = new a.instance({'x': 1, 'y': 2});
常量構(gòu)造函數(shù)
var a = const ImmutablePoint(1, 1);
var b = const ImmutablePoint(1, 1);
assert(identical(a, b)); // 它們是同一個實例赠堵。
在 常量上下文 中, 構(gòu)造函數(shù)或者字面量前的 const
可以省略法褥。 例如茫叭,下面代碼創(chuàng)建了一個 const 類型的 map 對象:
// 這里有很多的 const 關(guān)鍵字。
const pointAndLine = const {
'point': const [const ImmutablePoint(0, 0)],
'line': const [const ImmutablePoint(1, 10), const ImmutablePoint(-2, 11)],
};
// 僅有一個 const 半等,由該 const 建立常量上下文揍愁。
const pointAndLine = {
'point': [ImmutablePoint(0, 0)],
'line': [ImmutablePoint(1, 10), ImmutablePoint(-2, 11)],
};
/**************************************************************************/
var a = const ImmutablePoint(1, 1); // 創(chuàng)建一個常量對象
var b = ImmutablePoint(1, 1); // 創(chuàng)建一個非常量對象
assert(!identical(a, b)); // 兩者不是同一個實例!
構(gòu)造函數(shù)
class Point {
num x, y;
Point(num x, num y) {
// 還有更好的方式來實現(xiàn)下面代碼,敬請關(guān)注杀饵。
this.x = x;
this.y = y;
}
}
//兩種創(chuàng)建方式一樣
class Point {
num x, y;
// 在構(gòu)造函數(shù)體執(zhí)行前吗垮,
// 語法糖已經(jīng)設(shè)置了變量 x 和 y。
Point(this.x, this.y);
}
默認構(gòu)造函數(shù)
默認構(gòu)造函數(shù)沒有參數(shù)并會調(diào)用父類的無參構(gòu)造函數(shù)凹髓。
構(gòu)造函數(shù)不被繼承
子類不會繼承父類的構(gòu)造函數(shù)烁登。 子類不聲明構(gòu)造函數(shù),那么它就只有默認構(gòu)造函數(shù) (匿名蔚舀,沒有參數(shù)) 饵沧。
命名構(gòu)造函數(shù)
一個類可以實現(xiàn)多個構(gòu)造函數(shù):
class Point {
num x, y;
Point(this.x, this.y);
// 命名構(gòu)造函數(shù)
Point.origin() {
x = 0;
y = 0;
}
}
切記,構(gòu)造函數(shù)不能夠被繼承赌躺, 這意味著父類的命名構(gòu)造函數(shù)不會被子類繼承狼牺。 如果希望使用父類中定義的命名構(gòu)造函數(shù)創(chuàng)建子類, 就必須在子類中實現(xiàn)該構(gòu)造函數(shù)礼患。
初始化列表
// 在構(gòu)造函數(shù)體執(zhí)行之前是钥,
// 通過初始列表設(shè)置實例變量。
Point.fromJson(Map<String, num> json)
: x = json['x'],
y = json['y'] {
print('In Point.fromJson(): ($x, $y)');
}
Point.withAssert(this.x, this.y) : assert(x >= 0) {
print('In Point.withAssert(): ($x, $y)');
}
警告: 初始化程序的右側(cè)無法訪問 this
缅叠。
重定向構(gòu)造函數(shù)
class Point {
num x, y;
// 類的主構(gòu)造函數(shù)悄泥。
Point(this.x, this.y);
// 指向主構(gòu)造函數(shù)
Point.alongXAxis(num x) : this(x, 0);
}
常量構(gòu)造函數(shù)
class ImmutablePoint {
static final ImmutablePoint origin =
const ImmutablePoint(0, 0);
final num x, y;
const ImmutablePoint(this.x, this.y);
}
工廠構(gòu)造函數(shù)
當執(zhí)行構(gòu)造函數(shù)并不總是創(chuàng)建這個類的一個新實例時,則使用 factory
關(guān)鍵字肤粱。 例如弹囚,一個工廠構(gòu)造函數(shù)可能會返回一個 cache 中的實例, 或者可能返回一個子類的實例领曼。
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);
}
}
//工廠構(gòu)造函的調(diào)用方式與其他構(gòu)造函數(shù)一樣:
var logger = Logger('UI');
logger.log('Button clicked');
提示: 工廠構(gòu)造函數(shù)無法訪問 this庶骄。
獲取對象的類型
使用對象的 runtimeType
屬性毁渗, 可以在運行時獲取對象的類型, runtimeType
屬性回返回一個 Type 對象单刁。
實例變量
class Point {
num x; // 聲明示例變量 x灸异,初始值為 null 。
num y; // 聲明示例變量 y,初始值為 null 绎狭。
num z = 0; // 聲明示例變量 z细溅,初始值為 0 。
}
所有實例變量都生成隱式 getter 方法儡嘶。 非 final 的實例變量同樣會生成隱式 setter 方法喇聊。
方法
實例方法
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);
}
}
Getter 和 Setter
Dart 會為變量提供隱形 Getter 和 Setter ,但是也可以使用 get
和 set
關(guān)鍵字實現(xiàn) Getter 和 Setter :
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 方法誓篱,都能夠正確的執(zhí)行。 為了避免一些問題凯楔,操作符只調(diào)用一次 getter 方法窜骄, 然后把值保存到一個臨時的變量中。
抽象方法
同 Java 中的實現(xiàn):
abstract class Doer {
// 定義實例變量和方法 ...
void doSomething(); // 定義一個抽象方法摆屯。
}
class EffectiveDoer extends Doer {
void doSomething() {
// 提供方法實現(xiàn)邻遏,所以這里的方法就不是抽象方法了...
}
}
抽象類
使用 abstract
修飾符來定義 抽象類 — 抽象類不能實例化。 抽象類通常用來定義接口虐骑,以及部分實現(xiàn)准验。 如果希望抽象類能夠被實例化,那么可以通過定義一個 工廠構(gòu)造函數(shù) 來實現(xiàn)廷没。
// 這個類被定義為抽象類糊饱,
// 所以不能被實例化。
abstract class AbstractContainer {
// 定義構(gòu)造行數(shù)颠黎,字段另锋,方法...
void updateChildren(); // 抽象方法。
}
隱式接口
同 Java 中的接口:
// person 類狭归。 隱式接口里面包含了 greet() 方法聲明夭坪。
class Person {
// 包含在接口里,但只在當前庫中可見唉铜。
final _name;
// 不包含在接口里台舱,因為這是一個構(gòu)造函數(shù)律杠。
Person(this._name);
// 包含在接口里潭流。
String greet(String who) => 'Hello, $who. I am $_name.';
}
// person 接口的實現(xiàn)。
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()));
}
//實現(xiàn)多接口
class Point implements Comparable, Location {...}
擴展類(繼承)
同 Java :
class Television {
void turnOn() {
_illuminateDisplay();
_activateIrSensor();
}
// ···
}
class SmartTelevision extends Television {
void turnOn() {
super.turnOn();
_bootNetworkInterface();
_initializeMemory();
_upgradeApps();
}
// ···
}
重寫類成員
同 Java:
class SmartTelevision extends Television {
@override
void turnOn() {...}
// ···
}
重寫運算符
這個就很神器柜去,用代碼來說明吧灰嫉,下面示例演示一個類重寫 +
和 -
操作符
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);
// 運算符 == 和 hashCode 部分沒有列出。 有關(guān)詳情嗓奢,請參考下面的注釋讼撒。
// ···
}
void main() {
final v = Vector(2, 3);
final w = Vector(2, 2);
assert(v + w == Vector(4, 5));
assert(v - w == Vector(0, 1));
}
可被重寫的運算符
| <
| +
| |
| []
|
| ---- | ---- | ---- | ----- |
| >
| /
| ^
| []=
|
| <=
| ~/
| &
| ~
|
| >=
| *
| <<
| ==
|
| –
| %
| >>
| |
提示: 你可能會被提示 !=
運算符為非可重載運算符。 因為 e1 != e2
表達式僅僅是 !(e1 == e2)
的語法糖。
noSuchMethod()
當代碼嘗試使用不存在的方法或?qū)嵗兞繒r根盒, 通過重寫 noSuchMethod()
方法钳幅,來實現(xiàn)檢測和應對處理:
class A {
// 如果不重寫 noSuchMethod,訪問
// 不存在的實例變量時會導致 NoSuchMethodError 錯誤炎滞。
@override
void noSuchMethod(Invocation invocation) {
print('You tried to use a non-existent member: ' +
'${invocation.memberName}');
}
}
枚舉類型
同 Java:
enum Color { red, green, blue }
//枚舉中存在一個值 index 返回值為枚舉類型定義中的位置
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);
//可以在 switch 語句 中使用枚舉
var aColor = Color.blue;
switch (aColor) {
case Color.red:
print('Red as roses!');
break;
case Color.green:
print('Green as grass!');
break;
default: // 沒有這個敢艰,會看到一個警告。
print(aColor); // 'Color.blue'
}
混入(Mixin)
這個理解起來不算難册赛,我們寫一個例子:
class S {
a() {print("S.a");}
}
class A {
a(){print("A.a");}
b(){print("A.b");}
}
class B {
a(){print("B.a");}
b(){print("B.b");}
c(){print("B.c ");}
}
class T = B with A, S;
main(List<String> args) {
T t = new T();
t.a();
t.b();
t.c();
}
//輸出
S.a
A.b
B.c
靜態(tài)
Dart 和 Java 中的靜態(tài)是一樣的钠导;