類
Dart作為一門(mén)面向?qū)ο蟮木幊陶Z(yǔ)言碍扔,類充當(dāng)了一個(gè)非常重要的角色涨缚。
Dart中一切皆為對(duì)象轮傍,而每個(gè)對(duì)象都是一個(gè)類的實(shí)例,所有的類都繼承于Object
首装。
實(shí)例變量
以下是一個(gè)描述人的類创夜,其中有name
、sex
仙逻、age
三個(gè)實(shí)例變量驰吓,如下所示:
class People {
String name; //聲明實(shí)例變量name涧尿,初始值為null
int sex =1; //聲明實(shí)例變量name,初始值為1
int age = 0; //聲明實(shí)例變量age檬贰,初始化為0
}
所有的實(shí)例變量都會(huì)自動(dòng)生成一個(gè)getter
方法姑廉,沒(méi)有聲明為final
的實(shí)例變量還會(huì)生成一個(gè)setter
方法。所以我們可以直接 調(diào)用 (示例.屬性 )來(lái)訪問(wèn) 和 賦值變量
構(gòu)造方法
默認(rèn)構(gòu)造方法
定義了一個(gè)類的時(shí)候就會(huì)自動(dòng)生成一個(gè)無(wú)參的構(gòu)造方法翁涤,如果需要?jiǎng)e的參數(shù)的構(gòu)造方法桥言,可以自己定義,如下所示:
class People {
String name;
int sex =1;
int age = 0;
People() {
//默認(rèn)會(huì)生成
}
}
main() {
People p1 = new People();
p1.name = "test";
p1.sex = 2;
p1.age = 3;
}
看到默認(rèn)會(huì)生成一個(gè)構(gòu)造方法葵礼,也許OC/java程序員就會(huì)想到一個(gè)問(wèn)題号阿,他是不是能重載?
事實(shí)上鸳粉,Dart的方法時(shí)不支持重載的扔涧,如下所示,是錯(cuò)誤的代碼示范
class People {
String name;
int sex =1;
int age = 0;
People() {
//默認(rèn)會(huì)生成
}
People(String name , int sex ,int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
}
那么届谈,如果dart里面需要多個(gè)構(gòu)造方法怎么辦枯夜?
這就是下面的“命名構(gòu)造方法”。
命名構(gòu)造方法
class People {
String name;
int sex =1;
int age = 0;
People.formNSA(String name , int sex ,int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
}
dart提供了一個(gè)語(yǔ)法糖來(lái)進(jìn)行一些構(gòu)造方法簡(jiǎn)寫(xiě):
People.formNSA(String name , int sex ,int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
}
可以寫(xiě)成:
People.formNSA(this.name ,this.sex ,this.age);
需要注意的是:子類不會(huì)繼承父類的構(gòu)造方法艰山。子類如果沒(méi)有定義構(gòu)造方法湖雹,則只有一個(gè)默認(rèn)的構(gòu)造方法。
調(diào)用父類的構(gòu)造方法
默認(rèn)情況下程剥,子類的構(gòu)造方法會(huì)自動(dòng)調(diào)用父類的默認(rèn)構(gòu)造方法劝枣。父類的構(gòu)造方法在子類構(gòu)造方法開(kāi)始執(zhí)行的位置調(diào)用。
如下是定義一個(gè)People
的子類Adults
的示例:
class People {
String name;
int sex =1;
int age = 0;
People(this.name ,this.sex ,this.age){
print("I am a human being");
}
}
class Adults extends People{
String work;
Adults(String name, int sex, int age,this.work) : super(name, sex, age){
print("I'm an adult");
}
}
main() {
var cp = new Adults("test", 2, 20, 'developer');
}
那么控制臺(tái)將輸出以下信息:
I am a human being
I'm an adult
初始化參數(shù)列表
如果提供了一個(gè)initializer list
(初始化參數(shù)列表)织鲸,則初始化參數(shù)列表會(huì)在父類構(gòu)造方法執(zhí)行之前執(zhí)行舔腾,他們之間的執(zhí)行順序如下:
- 初始化參數(shù)列表
- 父類構(gòu)造方法
- 主類構(gòu)造方法
初始化列表非常適合用來(lái)設(shè)置final變量的值,下面是算出體質(zhì)是什么類型(瘦,標(biāo)準(zhǔn),胖)的例子:
import 'dart:math';
enum Constitution {
thin,
standard,
fat
}
class People {
String name;
int weight =1;
int height = 0;
Constitution Physique;
People(name ,weight ,height)
: name = name,
weight = weight,
height = height,
Physique = ( ( (height-80)*.7)-weight ) > 5? Constitution.thin : ( ( (height-80)*.7)-weight ) < 5? Constitution.fat : Constitution.standard;
}
main() {
var p = new People("test", 60, 174);
print(p.Physique);
}
重定向構(gòu)造函數(shù)
? 有時(shí)候一個(gè)構(gòu)造函數(shù)會(huì)調(diào)動(dòng)類中的其他構(gòu)造函數(shù)(在Java中就是 this(...)
)搂擦。 一個(gè)重定向構(gòu)造函數(shù)是沒(méi)有代碼的稳诚,在構(gòu)造函數(shù)聲明后,使用 冒號(hào)調(diào)用其他構(gòu)造函數(shù)瀑踢。
class People {
String name;
int weight =1;
int height = 0;
People(this.weight, this.height);
People.wh(int weight,int height):this(weight,height); ///調(diào)用上面的構(gòu)造函數(shù)
}
常量構(gòu)造方法
如果你需要提供一個(gè)狀態(tài)不變的對(duì)象扳还,并在編譯時(shí)將這些對(duì)象編譯為常量。
做到這些橱夭,只需要定義一個(gè)const
構(gòu)造方法氨距,并且把所有變量聲明為final
類型。
class Oldman {
final int age;
const Oldman(this.age);
}
void main(){
//編譯器常量
var p1 = const Oldman(60);
var p2 = const Oldman(60);
print(p1 == p2); // true
}
工廠構(gòu)造函數(shù)
? 當(dāng)實(shí)現(xiàn)一個(gè)使用factory
關(guān)鍵詞修飾的構(gòu)造函數(shù)時(shí)棘劣,這個(gè)構(gòu)造函數(shù)不必創(chuàng)建類的新實(shí)例俏让。例如,一個(gè)工廠構(gòu)造函數(shù) 可能從緩存中獲取一個(gè)實(shí)例并返回,或者 返回一個(gè)子類型的實(shí)例首昔。(工廠構(gòu)造函數(shù)無(wú)法訪問(wèn) this
)
class Logger {
final String name;
//從緩存獲取對(duì)象
static final Map _cache = {};
//工廠構(gòu)造函數(shù)寡喝,無(wú)法使用this變量
factory Logger(String name) {
if (_cache.containsKey(name)) {
//工廠構(gòu)造函數(shù)需要返回 Logger 實(shí)例對(duì)象
return _cache[name];
} else {
final logger = Logger._internal(name);
_cache[name] = logger;
return logger;
}
}
//以 _ 開(kāi)頭的函數(shù)、變量無(wú)法在庫(kù)外使用
Logger._internal(this.name);
}
? 借助工廠構(gòu)造函數(shù)能夠?qū)崿F(xiàn)單例:
/使用工廠構(gòu)造實(shí)現(xiàn)單例
class Manager {
static Manager _instance;
//和static是一樣的, 區(qū)別是factory畢竟是構(gòu)造函數(shù)勒奇,需要返回一個(gè)實(shí)例预鬓,而static是靜態(tài)方法。
factory Manager.getInstance() {
if (_instance == null) {
_instance = new Manager._internal();
}
return _instance;
}
Manager._internal();
}
可以看到上面示例代碼中默認(rèn)構(gòu)造方法前面還有個(gè)factory
赊颠,這個(gè)關(guān)鍵字代表著這是個(gè)工廠構(gòu)造方法格二。
要注意的是工廠構(gòu)造方法時(shí)沒(méi)法訪問(wèn)this
關(guān)鍵字的,所以上面就有了在類的內(nèi)部這么調(diào)用構(gòu)造方法的代碼:final logger = new Logger._internal(name);
巨税,在上面工廠構(gòu)造方法中蟋定,如果緩存中存在傳入的name
的key值,則取出緩存中的對(duì)應(yīng)value返回草添。如果緩存中沒(méi)找到驶兜,就會(huì)通過(guò)命名構(gòu)造方法來(lái)新建一個(gè)對(duì)象,緩存起來(lái)后返回远寸。
Getters 和 Setters
? Dart中每個(gè)實(shí)例變量都隱含的具有一個(gè) getter抄淑, 如果變量不是 final 的則還有一個(gè) setter〕酆螅可以通過(guò)實(shí)現(xiàn) getter 和 setter 來(lái)創(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定義了一個(gè) 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中使用自身會(huì)導(dǎo)致Stack Overflow
可覆寫(xiě)的操作符
? 把已經(jīng)定義的垫竞、有一定功能的操作符進(jìn)行重新定義∪紫埃可以重新定義的操作符有:
| <
| +
| |
| []
|
| ---- | ---- | ---- | ----- |
| >
| /
| ^
| []=
|
| <=
| ~/
| &
| ~
|
| >=
| *
| <<
| ==
|
| –
| %
| >>
| |
? 比如:List就重寫(xiě)了 []
夜涕。
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
關(guān)鍵字定義犯犁,是不能被實(shí)例化的,通常用來(lái)定義接口以及部分實(shí)現(xiàn)女器。
但與其他語(yǔ)言不太一樣的地方是酸役,抽象方法也可以定義在非抽象類中,如下例子所示:
abstract class Bird {
void fly(); //抽象方法驾胆,不需要在方法前聲明 abstract`
}
class Sparrow extends Bird {
void fly() {
}
void sleep();
}
接口
? 與Java不同涣澡,Dart中沒(méi)有interface
關(guān)鍵字,Dart中每個(gè)類都隱式的定義了一個(gè)包含所有實(shí)例成員的接口丧诺, 并且這個(gè)類實(shí)現(xiàn)了這個(gè)接口入桂。如果你想 創(chuàng)建類 A 來(lái)支持 類 B 的 方法,而不想繼承 B 的實(shí)現(xiàn)驳阎, 則類 A 應(yīng)該實(shí)現(xiàn) B 的接口抗愁。
class Listener{
void onComplete(){}
void onFailure(){}
}
class MyListsner implements Listener{
MyListsner(){
}
@override
void onComplete() {
}
@override
void onFailure() {
}
}
與繼承的區(qū)別在于:
1惕艳、單繼承,多實(shí)現(xiàn)驹愚。
2、繼承可以有選擇的重寫(xiě)父類方法并且可以使用super
劣纲,實(shí)現(xiàn)強(qiáng)制重新定義接口所有成員逢捺。
可調(diào)用的類
? 如果 Dart 類實(shí)現(xiàn)了 call()
函數(shù)則 類的實(shí)例 可以當(dāng)做方法來(lái)調(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 實(shí)現(xiàn)了多繼承 是一種在多類繼承中重用一個(gè)類代碼的方法癞季。 它的基本 形式如下
//被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
擁有了三個(gè)方法(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 {}
//可以簡(jiǎn)寫(xiě)成:
//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彌補(bǔ)了接口和繼承的不足伺绽,繼承只能單繼承,而接口無(wú)法復(fù)用實(shí)現(xiàn)嗜湃,mixins卻可以多混入并且能利用到混入類的具體實(shí)現(xiàn):
abstract class Swimming{
void swimming(){
print("游泳");
}
}
abstract class Jump{
void jump(){
print("跳躍");
}
}
//只能單繼承奈应,如果需要Jump,只能以implements的形式
class Test extends Swimming implements Jump{
//實(shí)現(xiàn)接口
void jump(){
print("跳躍");
}
}
//但是實(shí)際上购披,我們經(jīng)常不需要重新實(shí)現(xiàn)Jump方法杖挣,復(fù)用Jump所實(shí)現(xiàn)的jump方法就可以了
//這時(shí)使用混合能夠更加方便
class Test with Swimming, Jump {}
轉(zhuǎn)載:姜姜和張張
原文地址
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán)刚陡,非商業(yè)轉(zhuǎn)載請(qǐng)注明出處惩妇。