類
? Dart 是一個面向?qū)ο缶幊陶Z言。 每個對象都是一個類的實例,所有的類都繼承于 Object。
//每個實例變量都會自動生成一個 getter 方法(隱含的)。 非final 實例變量還會自動生成一個 setter 方法。
class Point {
num x;
num y;
}
構(gòu)造函數(shù)
? 由于把構(gòu)造函數(shù)參數(shù)賦值給實例變量的場景太常見了, Dart 提供了一個語法糖來簡化這個操作:
class Point {
num x;
num y;
Point(this.x, this.y);
}
命名構(gòu)造函數(shù)
? Dart 并不支持構(gòu)造函數(shù)的重載,而采用了命名構(gòu)造函數(shù)為一個類實現(xiàn)多個構(gòu)造函數(shù):
class Point {
num x;
num y;
Point(this.x, this.y);
Point(this.y);///錯誤,不允許重載
//命名構(gòu)造函數(shù)
Point.y(this.y) {
x = 0;
}
}
//使用
var p = Point.y(0);
初始化列表
? 在構(gòu)造函數(shù)函數(shù)體執(zhí)行之前會首先執(zhí)行初始化列表,非常適合用來設(shè)置 final 變量的值。
class Point {
num x;
num y;
Point(this.x, this.y);
//命名構(gòu)造函數(shù)
Point.y(this.y) {
x = 0;
}
Point.fromMap(Map map)
: x = map['x'], // : 和c++一樣,初始化列表
y = map['y'];
Point.x(int i)
: x = i,
y = 0;
}
重定向構(gòu)造函數(shù)
? 有時候一個構(gòu)造函數(shù)會調(diào)動類中的其他構(gòu)造函數(shù)(在Java中就是 this(...))。 一個重定向構(gòu)造函數(shù)是沒有代碼的,在構(gòu)造函數(shù)聲明后,使用 冒號調(diào)用其他構(gòu)造函數(shù)。
class Point {
num x;
num y;
Point(this.x, this.y);
Point.xy(int x,int y):this(x,y); ///調(diào)用上面的構(gòu)造函數(shù)
}
常量構(gòu)造函數(shù)
? 如果你的類提供一個狀態(tài)不變的對象,你可以把這些對象 定義為編譯時常量。要實現(xiàn)這個功能,需要定義一個 const 構(gòu)造函數(shù), 并且聲明所有類的變量為 final。
class ImmutablePoint {
final num x;
final num y;
//常量構(gòu)造函數(shù)
const ImmutablePoint(this.x, this.y);
}
void main(){
//編譯器常量
var p1 = const ImmutablePoint(0,0);
var p2 = const ImmutablePoint(0,0);
print(p1 == p2); // true
}
工廠構(gòu)造函數(shù)
? 當實現(xiàn)一個使用factory 關(guān)鍵詞修飾的構(gòu)造函數(shù)時,這個構(gòu)造函數(shù)不必創(chuàng)建類的新實例。例如,一個工廠構(gòu)造函數(shù) 可能從緩存中獲取一個實例并返回,或者 返回一個子類型的實例。(工廠構(gòu)造函數(shù)無法訪問 this)
class Logger {
final String name;
//從緩存獲取對象
static final Map _cache = {};
//工廠構(gòu)造函數(shù),無法使用this變量
factory Logger(String name) {
if (_cache.containsKey(name)) {
//工廠構(gòu)造函數(shù)需要返回 Logger 實例對象
return _cache[name];
} else {
final logger = Logger._internal(name);
_cache[name] = logger;
return logger;
}
}
//以 _ 開頭的函數(shù)、變量無法在庫外使用
Logger._internal(this.name);
}
? 借助工廠構(gòu)造函數(shù)能夠?qū)崿F(xiàn)單例:
//使用工廠構(gòu)造實現(xiàn)單例
class Manager {
static Manager _instance;
//和static是一樣的, 區(qū)別是factory畢竟是構(gòu)造函數(shù),需要返回一個實例,而static是靜態(tài)方法。
factory Manager.getInstance() {
if (_instance == null) {
_instance = new Manager._internal();
}
return _instance;
}
// static Manager getInstance() {
// if (_instance == null) {
// _instance = new Manager._internal();
// }
// return _instance;
// }
Manager._internal();
}
Getters 和 Setters
? Dart中每個實例變量都隱含的具有一個 getter, 如果變量不是 final 的則還有一個 setter??梢酝ㄟ^實現(xiàn) getter 和 setter 來創(chuàng)建新的屬性, 使用 get 和 set 關(guān)鍵字定義 getter 和 setter:
class Rect {
num left;
num top;
num width;
num height;
Rect(this.left, this.top, this.width, this.height);
//使用 get定義了一個 right 屬性
num get right => left + width;
set right(num value) => left = value - width;
}
void main() {
var rect = Rect(0, 0, 10, 10);
print(rect.right); //10
rect.right = 15;
print(rect.left); //5
}
需要注意的是,在get與set中使用自身會導(dǎo)致Stack Overflow
可覆寫的操作符
? 把已經(jīng)定義的、有一定功能的操作符進行重新定義??梢灾匦露x的操作符有:
| < | + | | | [] |
| ---- | ---- | ---- | ----- |
| > | / | ^ | []= |
| <= | ~/ | & | ~ |
| >= | * | << | == |
| – | % | >> | |
? 比如:List就重寫了 []。
class Point {
int x;
int y;
//返回值 參數(shù)隨你定義
Point operator +(Point point) {
return Point(x + point.x, y + point.y);
}
Point(this.x, this.y);
}
var p1 = Point(1, 1);
var p2 = p1 + Point(2, 2);
print(p2.x); ///3
print(p2.y); ///3
抽象類
? 使用 abstract 修飾符定義一個抽象類。抽象類中允許出現(xiàn)無方法體的方法
abstract class Parent {
String name;
void printName(); //抽象方法,不需要在方法前聲明 abstract
}
? 抽象類不能被實例化,除非定義工廠方法并返回子類。
abstract class Parent {
String name;
//默認構(gòu)造方法
Parent(this.name);
//工廠方法返回Child實例
factory Parent.test(String name){
return new Child(name);
}
void printName();
}
// extends 繼承抽象類
class Child extends Parent{
Child(String name) : super(name);
@override
void printName() {
print(name);
}
}
void main() {
var p = Parent.test("test");
print(p.runtimeType); //輸出實際類型 Child
p.printName();
}
接口
? 與Java不同,Dart中沒有interface關(guān)鍵字,Dart中每個類都隱式的定義了一個包含所有實例成員的接口, 并且這個類實現(xiàn)了這個接口。如果你想 創(chuàng)建類 A 來支持 類 B 的 方法,而不想繼承 B 的實現(xiàn), 則類 A 應(yīng)該實現(xiàn) B 的接口。
class Listener{
void onComplete(){}
void onFailure(){}
}
class MyListsner implements Listener{
MyListsner(){
}
@override
void onComplete() {
}
@override
void onFailure() {
}
}
與繼承的區(qū)別在于:
1、單繼承,多實現(xiàn)。
2、繼承可以有選擇的重寫父類方法并且可以使用super,實現(xiàn)強制重新定義接口所有成員。
可調(diào)用的類
? 如果 Dart 類實現(xiàn)了 call() 函數(shù)則 可以當做方法來調(diào)用。
class Closure {
call(String a, String b) => '$a $b!';
}
main() {
var c = new Closure();
var out = c("Hello","Dart");
print(out);
}
混合mixins
? Mixins 是一種在多類繼承中重用 一個類代碼的方法。它的基本形式如下:
//被mixin(混入)的類不能有構(gòu)造函數(shù)
class A {
void a(){}
}
class B{
void b(){}
}
class C with A,B{
void c(){}
}
with后面跟著需要混入的類,被mixin(混入)的類不能有構(gòu)造函數(shù)。現(xiàn)在的 C擁有了三個方法(a、b與c)。假設(shè)A與B 存在相同的方法,以最右側(cè)的混入類為主,比如:
class A {
String getMessage() => 'A';
}
class B {
String getMessage() => 'B';
}
//
class AB with A, B {}
class BA with B, A {}
void printMessage(obj) => print(obj.getMessage());
void main() {
printMessage(AB()); //輸出 B
printMessage(BA()); //輸出 A
}
繼承與mixins是兼容的
class A {
String getMessage() => 'A';
}
class B {
String getMessage() => 'B';
}
class P{
String getMessage() => 'P';
}
class AB extends P with A, B {}
class BA extends P with B, A {}
//可以簡寫成:
//class AB = P with A, B;
//class BA = P with B, A;
void printMessage(obj) => print(obj.getMessage());
void main() {
printMessage(AB()); //輸出 B
printMessage(BA()); //輸出 A
}
? mixins彌補了接口和繼承的不足,繼承只能單繼承,而接口無法復(fù)用實現(xiàn),mixins卻可以多混入并且能利用到混入類的具體實現(xiàn):
abstract class Swimming{
void swimming(){
print("游泳");
}
}
abstract class Jump{
void jump(){
print("跳躍");
}
}
//只能單繼承,如果需要Jump,只能以implements的形式
class Test extends Swimming implements Jump{
//實現(xiàn)接口
void jump(){
print("跳躍");
}
}
//但是實際上,我們經(jīng)常不需要重新實現(xiàn)Jump方法,復(fù)用Jump所實現(xiàn)的jump方法就可以了
//這時使用混合能夠更加方便
class Test with Swimming, Jump {}