前文鏈接:
內(nèi)容:
- 函數(shù)(方法)
函數(shù)定義及各類函數(shù)通熄;函數(shù)參數(shù)耙旦;閉包 - 面向?qū)ο?br>
定義脱羡;構(gòu)造函數(shù);成員(變量與函數(shù))
繼承與多態(tài)免都;抽象類锉罐;接口;枚舉類
Mixins绕娘;操作符 - 泛型
定義脓规;用法;限制泛型類型 - 庫(kù)和可見(jiàn)性
- 異常
- 元數(shù)據(jù)
五险领、函數(shù)(方法)
1侨舆、說(shuō)明:
Dart 是一個(gè)真正的面向?qū)ο笳Z(yǔ)言,方法也是對(duì)象并且具有一種類型绢陌,
Function
态罪。這意味著,方法可以賦值給變量下面,也可以當(dāng)做其他方法的參數(shù)。也可以把 Dart 類的實(shí)例當(dāng)做方法來(lái)調(diào)用绩聘。 詳情請(qǐng)參考 Callable classes沥割。
方法都有返回值,當(dāng)沒(méi)有指定返回值的時(shí)候凿菩,函數(shù)返回null机杜,即最后默認(rèn)執(zhí)行一句
return null
,可以省略不寫(xiě)衅谷。
2椒拗、函數(shù)定義及各類函數(shù):
-
基本形式:
返回值 方法名(參數(shù)1, 參數(shù)2, ...) { 方法體 return 返回值; }
示例:
int sum(int a, int b) { return a + b; }
-
省略模式:
1、定義方法的返回值類型 和 參數(shù) 都可以省略sum(a, b) { return a + b; } //sumResult = 9 print("sumResult = ${sum(3, 6)}");
說(shuō)明:建議明確方法(函數(shù))的輸入類型和返回值類型,既便于修改蚀苛,也方便閱讀在验。重要的是,如果不寫(xiě)方法參數(shù)輸入類型堵未,則在調(diào)用的時(shí)候腋舌,調(diào)用者可能無(wú)法明確參數(shù)類型(經(jīng)測(cè)試,在編譯階段并未有相應(yīng)的參數(shù)類型的檢查提示)渗蟹,這就可能導(dǎo)致
Unhandled exception
之類的錯(cuò)誤块饺。 -
箭頭函數(shù):
1、語(yǔ)法:=> expr
2雌芽、是{ return expr; }
形式的縮寫(xiě)授艰。=>
形式 有時(shí)候也稱之為 胖箭頭 語(yǔ)法。
注:只適用于一個(gè)表達(dá)式
的方法世落。
3淮腾、示例:int sum(int a, int b) => a + b;
-
匿名函數(shù):
1、沒(méi)有名字的函數(shù)岛心,稱之為匿名函數(shù)
来破,有時(shí)候也被稱為lambda
或者closure 閉包
。
2忘古、你可以把匿名函數(shù)賦值給一個(gè)變量徘禁, 然后你可以通過(guò)這個(gè)變量使用這個(gè)函數(shù)。
3髓堪、匿名函數(shù)和命名函數(shù)看起來(lái)類似送朱,在括號(hào)之間可以定義一些參數(shù),參數(shù)使用逗號(hào)分割干旁,也可以是可選參數(shù)驶沼,大括號(hào)中的代碼為函數(shù)體。- 定義:
([[Type] param1[, …]]) { codeBlock; };
- 示例:
Function sum = (int a, int b) { return a + b; }; //sum = 9 print("sum = ${sum(3, 6)}"); var list = ['apples', 'oranges', 'grapes', 'bananas', 'plums']; //其中forEach接收一個(gè)函數(shù) list.forEach((i) => print(list.indexOf(i).toString() + ': ' + i));
- 定義:
-
入口函數(shù):
1争群、每個(gè)應(yīng)用都需要有個(gè)頂級(jí)的main()
入口方法才能執(zhí)行回怜。main()
方法的返回值為void
并且有個(gè)可選的List<String>
參數(shù)。void main(List<String> args) { print(arguments); }
通過(guò)命令行可以將參數(shù)打印出來(lái):
入口函數(shù)調(diào)用
說(shuō)明:其中使用dart
命令調(diào)用换薄,參數(shù)用空格隔開(kāi) -
函數(shù)別名
1玉雾、在 Dart 語(yǔ)言中,方法也是對(duì)象轻要。
2复旬、使用typedef
, 或者function-type alias
來(lái)為方法類型命名, 然后可以使用命名的方法冲泥。
3驹碍、當(dāng)把方法類型賦值給一個(gè)變量的時(shí)候壁涎,typedef
保留類型信息。- 看下面一個(gè)簡(jiǎn)單的例子:
typedef int compare(int a, int b); int sort(int a, int b) { return a - b; } void main(List<String> args) { //(int, int) => int print(compare); //Closure: (int, int) => int from Function 'sort': static. print(sort); //true print(sort is Function); //true print(sort is compare); }
說(shuō)明:通過(guò)
is
操作符可以判斷兩個(gè)對(duì)象是否相等志秃。- 看下面的例子:
下面的代碼沒(méi)有使用 typedef:
class SortedCollection { Function compare; SortedCollection(int f(Object a, Object b)) { compare = f; } } // Initial, broken implementation. int sort(Object a, Object b) => 0; main() { SortedCollection coll = new SortedCollection(sort); // 我們只知道 compare 是一個(gè) Function 類型怔球, // 但是不知道具體是何種 Function 類型? assert(coll.compare is Function); }
說(shuō)明:當(dāng)把
f
賦值給compare
的時(shí)候洽损, 類型信息丟失了庞溜。f
的類型是(Object, Object) → int
(這里 → 代表返回值類型), 當(dāng)然該類型是一個(gè)Function
碑定。
如果我們使用顯式的名字并保留類型信息流码, 開(kāi)發(fā)者和工具可以使用 這些信息:typedef int Compare(Object a, Object b); class SortedCollection { Compare compare; SortedCollection(this.compare); } // Initial, broken implementation. int sort(Object a, Object b) => 0; main() { SortedCollection coll = new SortedCollection(sort); assert(coll.compare is Function); assert(coll.compare is Compare); }
- 注意: 目前,typedefs 只能使用在 function 類型上延刘,但是將來(lái) 可能會(huì)有變化漫试。
3、函數(shù)參數(shù)
-
靜態(tài)作用域
1碘赖、Dart 是靜態(tài)作用域語(yǔ)言驾荣,變量的作用域在寫(xiě)代碼的時(shí)候就確定過(guò)了。
2普泡、基本上大括號(hào)里面定義的變量就 只能在大括號(hào)里面訪問(wèn)播掷,和Java 作用域
類似。var topLevel = true; main() { var insideMain = true; myFunction() { var insideFunction = true; nestedFunction() { var insideNestedFunction = true; print(topLevel); //true print(insideMain); //true print(insideFunction); //true print(insideNestedFunction); //true } //undefined name 'insideNestedFunction' //print(insideNestedFunction); nestedFunction(); } //undefined name 'insideFunction' //print(insideFunction); myFunction(); }
-
可選參數(shù)
1.可選參數(shù)包括:可選命名參數(shù) 和 可選位置參數(shù)
2.但是這兩種參數(shù)不能同時(shí)當(dāng)做可選參數(shù)撼班。
3.可選參數(shù)的方法歧匈,在調(diào)用的時(shí)候,是可選的砰嘁,可傳入可不傳入
4.可選參數(shù)只能放到方法參數(shù)的末尾件炉,不能放到必需參數(shù)的前面- 可選命名參數(shù):
定義方法時(shí),可選命名參數(shù)需要將可選的參數(shù)放到{}
中
調(diào)用方法時(shí)矮湘,方法中的參數(shù)可以通過(guò)這種形式paramName: value
來(lái)指定命名參數(shù)
main() { //name:張三斟冕;isMan:null;age:null printArgs("張三"); //name:李四缅阳;isMan:false磕蛇;age:null printArgs("李四", isMan: false); //name:王五;isMan:null十办;age:88 printArgs("王五", age: 88); //name:趙六孤里;isMan:true;age:55 printArgs("趙六", isMan: true, age: 55); } void printArgs(String name, {bool isMan, int age}) { print("name:$name橘洞;isMan:$isMan;age:$age"); }
- 可選位置參數(shù):
定義方法時(shí)说搅,可選位置參數(shù)需要將可選的參數(shù)放到[]
中
調(diào)用方法時(shí)炸枣,方法中的參數(shù)根據(jù)位置來(lái)指定命名參數(shù)
main() { //name:張三;isMan:null;age:null printArg("張三"); //name:李四适肠;isMan:true霍衫;age:null printArg("李四", true); //無(wú)法調(diào)用 //printArg("王五", 29); //name:趙六;isMan:true侯养;age:29 printArg("趙六", true, 29); } void printArg(String name, [bool isMan, int age]) { print("name:$name敦跌;isMan:$isMan;age:$age"); }
- 可選命名參數(shù):
-
默認(rèn)參數(shù)值
1逛揩、在定義方法的時(shí)候柠傍,可以使用 = 來(lái)定義可選參數(shù)的默認(rèn)值。
2辩稽、默認(rèn)值只能是編譯時(shí)常量惧笛。
3、如果沒(méi)有提供默認(rèn)值逞泄,則默認(rèn)值為 null患整。void main() { //name:張三;age:39喷众;isMain:true printArgs("張三", 39); //name:Lili各谚;age:33;isMain:false printArgs("Lili", 33, isMan: false); } void printArgs(String name, int age, { bool isMan=true }) { print("name:$name到千;age:$age昌渤;isMain:$isMan"); }
-
測(cè)試函數(shù)是否相等
下面是測(cè)試頂級(jí)方法、靜態(tài)函數(shù)和實(shí)例函數(shù) 相等的示例:foo() {} // 一個(gè)頂級(jí)方法 class A { static void bar() {} // 一個(gè)靜態(tài)方法 void baz() {} // 一個(gè)實(shí)例方法 } main() { var x; // 比較 頂級(jí)方法. x = foo; print(foo == x); // 比較靜態(tài)方法 x = A.bar; print(A.bar == x); // 比較實(shí)例方法 var v = new A(); // A的第一個(gè)實(shí)例#1 var w = new A(); // A的第二個(gè)實(shí)例#2 var y = w; x = w.baz; // 這些閉包引用同一個(gè)實(shí)例(#2)父阻,因此它們是相等的 print(y.baz == x); // 這些閉包引用不同的實(shí)例愈涩,因此它們不等 print(v.baz != w.baz); }
4、閉包
特性:
1加矛、一個(gè)閉包
是一個(gè)方法對(duì)象履婉。
2、閉包定義在其他方法的內(nèi)部斟览,一般通過(guò)return
將其作為返回值返回毁腿。
3、不管閉包對(duì)象(方法返回的)在何處被調(diào)用苛茂,該對(duì)象都可以訪問(wèn)其(即閉包所在的方法)作用域內(nèi)的變量已烤,并持有其狀態(tài)。-
示例:
void test() { Function add = makeAdder(1); int result = add(2); //result = 3 print("result = $result"); } /** * 定義返回方法的函數(shù) */ Function makeAdder(num outerNum) { return (num innerNum)=> outerNum + innerNum; }
-
一段有意思的代碼:
void main() { var callbacks = []; for (var i = 0; i < 3; i++) { // 在列表 callbacks 中添加一個(gè)函數(shù)對(duì)象妓羊,這個(gè)函數(shù)會(huì)記住 for 循環(huán)中當(dāng)前 i 的值胯究。 callbacks.add(() => print('Save $i')); } //[Closure: () => void, Closure: () => void, Closure: () => void] print(callbacks); callbacks.forEach((c) => c()); // 分別輸出 Save 0 1 2 }
說(shuō)明:
-
for
循環(huán)中,向callbacks
中加入的是一個(gè)匿名函數(shù)
(此處定義的匿名函數(shù)的作用是打印局部變量i
)躁绸,此函數(shù)持有循環(huán)中的變量i
(一般的裕循,i
作為局部變量臣嚣,循環(huán)結(jié)束就被回收了),即閉包的特性(持有外部方法中變量的狀態(tài))剥哑。 -
forEach
函數(shù)接收的是一個(gè)函數(shù)對(duì)象(匿名函數(shù):(c) => c()
)作為參數(shù)硅则,每次循環(huán)進(jìn)行調(diào)用此函數(shù),即為callbacks
數(shù)組中的函數(shù)對(duì)象株婴。
-
六怎虫、面向?qū)ο?/h1>
1、定義
- Dart 是一個(gè)面向?qū)ο缶幊陶Z(yǔ)言困介,同時(shí)支持基于
mixin
的繼承機(jī)制大审。
- 每個(gè)對(duì)象都是一個(gè)類的實(shí)例,所有的類都繼承于 Object逻翁。
-
基于 Mixin 的繼承 意味著每個(gè)類(Object 除外) 都只有一個(gè)超類饥努,一個(gè)類的代碼可以在其他多個(gè)類繼承中重復(fù)使用。即一個(gè)類可以繼承自多個(gè)父類八回。
- 使用關(guān)鍵字
calss
聲明一個(gè)類
- 使用關(guān)鍵字
new
創(chuàng)建一個(gè)對(duì)象酷愧,new
可以省略。
- 對(duì)象的成員包括方法和數(shù)據(jù) (函數(shù) 和 實(shí)例變量)缠诅。
- 示例:
class Person {
}
void main() {
Person p = new Person();
//省略new關(guān)鍵字
Person pp = Person();
}
2溶浴、構(gòu)造函數(shù)
-
定義:
1、定義一個(gè)和類名字一樣的方法就定義了一個(gè)構(gòu)造函數(shù)管引。
2士败、還可以帶有其他可選的標(biāo)識(shí)符,形如ClassName.identifier
褥伴。
class Person {
Person() {
print("person===super");
}
}
class Student extends Person { //這里是繼承父類谅将,后面會(huì)總結(jié)
Student() {
print("student====this");
}
}
void main() {
Student s = Student();
//打印結(jié)果:
//person===super
//student====this
}
-
默認(rèn)構(gòu)造函數(shù)
1、如果未顯式定義構(gòu)造函數(shù)重慢,會(huì)默認(rèn)一個(gè)空的構(gòu)造函數(shù)饥臂。
2、默認(rèn)構(gòu)造函數(shù)沒(méi)有參數(shù)似踱,并且會(huì)調(diào)用超類的沒(méi)有參數(shù)的構(gòu)造函數(shù)隅熙。
class Person {
Person() {
print("person===super");
}
}
class Student extends Person { //這里是繼承父類,后面會(huì)總結(jié)
}
void main() {
Student s = Student();
//打印結(jié)果:
//person===super
}
-
自定義構(gòu)造函數(shù)
1核芽、如果存在自定義構(gòu)造函數(shù)囚戚,則默認(rèn)構(gòu)造函數(shù)無(wú)效,即只能存在一個(gè)構(gòu)造函數(shù)(這也驗(yàn)證了函數(shù)不能重載的特性)轧简。
2驰坊、其中this
關(guān)鍵字指當(dāng)前的實(shí)例。
class Person {
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
//報(bào)錯(cuò):The default constructor is already defined.
Person() {
print("person===super");
}
}
-
語(yǔ)法糖
1哮独、由于把構(gòu)造函數(shù)參數(shù)賦值給實(shí)例變量的場(chǎng)景太常見(jiàn)了庐橙, Dart 提供了一個(gè)語(yǔ)法糖來(lái)簡(jiǎn)化這個(gè)操作:
class Person {
String name;
int age;
/*
//常規(guī)寫(xiě)法
Person(String name, int age) {
this.name = name;
this.age = age;
}*/
//語(yǔ)法糖寫(xiě)法
Person(this.name, this.age);
}
-
命名構(gòu)造函數(shù)
- 說(shuō)明:
1假勿、使用命名構(gòu)造函數(shù)可以為一個(gè)類實(shí)現(xiàn)多個(gè)構(gòu)造函數(shù)
2、使用命名構(gòu)造函數(shù)來(lái)更清晰的表明你的意圖
3态鳖、構(gòu)造函數(shù)不能繼承,所以超類的命名構(gòu)造函數(shù)也不會(huì)被繼承恶导。
- 實(shí)現(xiàn)方式:
類名.方法
浆竭。其中方法名稱可以自定義
- 示例:
class Person {
String name;
int age;
//語(yǔ)法糖寫(xiě)法
Person(this.name, this.age);
//fromName名稱可以隨便起名
Person.fromName(String name) {
this.name = name;
}
//withAge名稱可以隨便起名
Person.withAge(int age) {
this.age = age;
}
void printArgs() {
print("name:$name;age:$age");
}
}
void main() {
Person p = Person("張三", 18);
//name:張三惨寿;age:18
p.printArgs();
Person pp = Person.fromName("李四");
//name:李四邦泄;age:null
pp.printArgs();
Person ppp = Person.withAge(33);
//name:null;age:33
ppp.printArgs();
}
-
常量構(gòu)造函數(shù)
- 說(shuō)明:
1裂垦、使用常量構(gòu)造函數(shù)可以創(chuàng)建編譯時(shí)常量顺囊,即類是不可變狀態(tài)。
2蕉拢、使用const
聲明構(gòu)造方法特碳,并且所有變量都為final
。
3晕换、要使用常量構(gòu)造函數(shù)只需要用 const 替代 new 即可午乓,也可以省略const
。
4闸准、兩個(gè)一樣的編譯時(shí)常量其實(shí)是 同一個(gè)對(duì)象(通過(guò)identical
可進(jìn)行對(duì)比)益愈。
- 示例:
class Person {
final String name;
final int age;
const Person(this.name, this.age);
void printArgs() {
print("name:$name;age:$age");
}
}
void main() {
const p = const Person("張三", 33);
const pp = const Person("張三", 33);
//true
print(identical(p, pp)); //比較兩個(gè)對(duì)象是否相等
}
-
工廠構(gòu)造函數(shù)
- 說(shuō)明:
1夷家、如果一個(gè)構(gòu)造函數(shù)并不總是返回一個(gè)新的對(duì)象蒸其,則可以將其定義為工廠構(gòu)造函數(shù)。
2库快、工廠構(gòu)造函數(shù)摸袁,類似于設(shè)計(jì)模式中的工廠模式。
3缺谴、在構(gòu)造方法前添加關(guān)鍵字factory
實(shí)現(xiàn)一個(gè)工廠構(gòu)造方法但惶。
4、在工廠構(gòu)造方法中可以返回對(duì)象湿蛔。
- 注意:工廠構(gòu)造函數(shù)無(wú)法訪問(wèn)
this
膀曾。
- 示例:
下面代碼演示工廠構(gòu)造函數(shù) 如何從緩存中返回對(duì)象。
class Logger {
final String name;
bool mute = false;
// _cache 是個(gè)庫(kù)私有變量阳啥,在變量名前加`_`即為私有成員變量
static final Map<String, Logger> _cache =
<String, Logger>{};
//添加 factory 定義為工廠構(gòu)造函數(shù)
factory Logger(String name) {
//如果緩存中有name添谊,則取出返回,若不存在則添加并返回察迟。
if (_cache.containsKey(name)) {
return _cache[name];
} else {
final logger = new Logger._internal(name);
_cache[name] = logger;
return logger;
}
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) {
print(msg);
}
}
}
調(diào)用:
var logger = new Logger('UI');
logger.log('Button clicked');
-
重定向構(gòu)造函數(shù)
- 說(shuō)明:
1斩狱、有時(shí)候一個(gè)構(gòu)造函數(shù)會(huì)調(diào)動(dòng)類中的其他構(gòu)造函數(shù)耳高,則可以通過(guò)重定向構(gòu)造函數(shù)。
2所踊、一個(gè)重定向構(gòu)造函數(shù)是沒(méi)有代碼的泌枪,在構(gòu)造函數(shù)聲明后,使用 :
調(diào)用其他構(gòu)造函數(shù)秕岛。
- 示例:
class Person {
String name;
int age;
//語(yǔ)法糖寫(xiě)法
Person(this.name, this.age);
Person.formAge(int age): this("張三", age);
//此種寫(xiě)法沒(méi)有給任何變量賦值碌燕,在調(diào)用后,name和age都為null
Person.initParams(String name, int age);
void printArgs() {
print("name:$name继薛;age:$age");
}
}
-
初始化列表
- 說(shuō)明:
1修壕、在構(gòu)造函數(shù)體執(zhí)行之前除了可以調(diào)用超類構(gòu)造函數(shù)之外,還可以初始化實(shí)例參數(shù)遏考。即初始化列表會(huì)在構(gòu)造方法體執(zhí)行前執(zhí)行慈鸠。
2、使用:
設(shè)置初始化表達(dá)式灌具,使用 ,
分隔初始化表達(dá)式青团。
3、初始化列表常用于設(shè)置final
變量的值稽亏。
官網(wǎng)警告: 初始化表達(dá)式等號(hào)右邊的部分不能訪問(wèn) this
壶冒。(本人驗(yàn)證,似乎并非如此截歉。)
- 示例:
官網(wǎng)示例:
class Point {
num x;
num y;
Point(this.x, this.y);
// Initializer list sets instance variables before
// the constructor body runs.
Point.fromJson(Map jsonMap)
: x = jsonMap['x'],
y = jsonMap['y'] {
print('In Point.fromJson(): ($x, $y)');
}
}
本地測(cè)試:
/**
* person
*/
class Person {
String name;
int age;
bool isMan;
//初始化列表胖腾,加上了this
Person(name, age):
this.name = name,
this.age = age;
//初始化列表,加上了this
Person.withMap(Map map): this.isMan = map["isMan"] {
this.name = map["name"];
this.age = map["age"];
}
void printArgs() {
print("name:$name瘪松;age:$age");
}
}
/**
* main
*/
import 'person.dart';
void main() {
Person p = new Person("張三", 33);
//name:張三咸作;age:33;isMan:null
p.printArgs();
Person pp = Person.withMap({
"name": "李四",
"age": 23,
"isMan": true});
//name:李四宵睦;age:23记罚;isMan:true
pp.printArgs();
}
注:
本人在測(cè)試的時(shí)候,在初始化列表上的變量加上了this
關(guān)鍵字壳嚎,編譯并未報(bào)錯(cuò)桐智,也可以正常執(zhí)行輸出結(jié)果。
這個(gè)地方不知是否是我的姿勢(shì)有誤烟馅,還是說(shuō)確實(shí)可以如此使用说庭,希望有知道的盆友可以解答我的困惑,非常感謝郑趁。
不過(guò)刊驴,一切以官方為準(zhǔn),最好不要加上this
- 設(shè)置
final
變量:
import 'dart:math';
class Point {
final num x;
final num y;
final num distanceFromOrigin;
Point(x, y)
: x = x,
y = y,
distanceFromOrigin = sqrt(x * x + y * y);
}
main() {
var p = new Point(2, 3);
print(p.distanceFromOrigin);
}
3、成員(變量與函數(shù))
說(shuō)明:
1捆憎、對(duì)象的成員包括方法和數(shù)據(jù) (函數(shù) 和 實(shí)例變量)舅柜。
2、當(dāng)你調(diào)用一個(gè)函數(shù)的時(shí)候躲惰,你是在一個(gè)對(duì)象上 調(diào)用:函數(shù)需要訪問(wèn)對(duì)象的方法 和數(shù)據(jù)致份。
3、所有沒(méi)有初始化的變量值都是 null础拨。
4知举、函數(shù)不能被重載,可以被子類覆寫(xiě)太伊。
-
調(diào)用:
- 使用點(diǎn)
.
來(lái)引用對(duì)象的變量或者方法。
- 使用
?.
來(lái)替代 .
可以避免當(dāng)左邊對(duì)象為 null
時(shí)候 拋出異常:
class Person {
//定義實(shí)例變量
String name;
int age;
//定義實(shí)例函數(shù)
void printArgs() {
print("name:${name}逛钻;age:${age}");
}
//演示方法不能被重載
//編譯錯(cuò)誤:The name 'printArgs' is already defined.
void printArgs(int age) {
print("name:${name}僚焦;age:${age}");
}
}
void main() {
Person p = new Person();
p.name = "張三";
p.age = 33;
//name:張三;age:33
p.printArgs();
Person pp;
pp?.name = "李四";
//報(bào)錯(cuò):Unhandled exception:
//NoSuchMethodError: The setter 'age=' was called on null.
//Receiver: null
//Tried calling: age=23
pp.age = 23;
}
-
實(shí)例變量
- 說(shuō)明:
1曙痘、所有沒(méi)有初始化的變量值都是 null芳悲。
2剧浸、每個(gè)實(shí)例變量都會(huì)自動(dòng)生成一個(gè) getter
方法(隱含的)彼硫。
3祠够、非final
變量會(huì)自動(dòng)生成一個(gè) setter
方法(隱含的)叽掘。
4殿漠、如果你在實(shí)例變量定義的時(shí)候初始化該變量(不是 在構(gòu)造函數(shù)或者其他方法中初始化)雇庙,該值是在實(shí)例創(chuàng)建的時(shí)候 初始化的掖鱼,也就是在構(gòu)造函數(shù)和初始化參數(shù)列 表執(zhí)行之前帮寻。
- 示例:
class Point {
num x;
num y;
}
main() {
var point = new Point();
point.x = 4; // 調(diào)用x旺订,是用了setter方法
assert(point.x == 4); // 調(diào)用x弄企,是用了getter方法
assert(point.y == null); // 變量默認(rèn)是null
}
-
實(shí)例函數(shù)
- 說(shuō)明
1、函數(shù)是類中定義的方法区拳,是類對(duì)象的行為拘领。
2、對(duì)象的實(shí)例函數(shù)可以訪問(wèn) this
樱调。
- 示例
import 'dart:math';
class Point {
num x;
num 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);
}
}
-
計(jì)算屬性-Getters And Setters
說(shuō)明
1约素、Getters 和 setters 是用來(lái)設(shè)置和訪問(wèn)對(duì)象屬性的特殊函數(shù)。
2笆凌、每個(gè)實(shí)例變量都隱含的具有一個(gè) getter
圣猎, 如果變量不是 final
的則還有一個(gè) setter
。
3菩颖、你可以通過(guò)實(shí)行 getter
和 setter
來(lái)創(chuàng)建新的屬性样漆, 使用 get
和 set
關(guān)鍵字定義 getter
和 setter
。
4晦闰、計(jì)算屬性的值是通過(guò)計(jì)算而來(lái)放祟,本身不存儲(chǔ)值鳍怨。
5、計(jì)算屬性賦值跪妥,其實(shí)是通過(guò)計(jì)算轉(zhuǎn)換到其他實(shí)例變量鞋喇。
6、在開(kāi)始使用實(shí)例變量眉撵,后來(lái)可以把實(shí)例變量用函數(shù)包裹起來(lái)侦香,而調(diào)用你代碼的地方不需要修改。
官網(wǎng)注意(本人此處還未搞明白什么意思)
1纽疟、像 (++
) 這種操作符不管是否定義 getter
都會(huì)正確的執(zhí)行罐韩。 為了避免其他副作用, 操作符只調(diào)用 getter
一次污朽,然后把其值保存到一個(gè)臨時(shí)變量中散吵。
-
示例
class Rectangle {
num left;
num top;
num width;
num height;
Rectangle(this.left, this.top, this.width, this.height);
// 定義兩個(gè)計(jì)算屬性: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;
}
main() {
var rect = new Rectangle(3, 4, 20, 15);
assert(rect.left == 3);
rect.right = 12;
assert(rect.left == -8);
}
-
類變量和類函數(shù)(靜態(tài)成員)
-
說(shuō)明
1、使用static
關(guān)鍵字來(lái)實(shí)現(xiàn)類級(jí)別的變量和函數(shù)
2蟆肆、靜態(tài)成員不能訪問(wèn)非靜態(tài)成員(this調(diào)用)矾睦,非靜態(tài)成員可以訪問(wèn)靜態(tài)成員。
[
靜態(tài)函數(shù)不再類實(shí)例上執(zhí)行炎功, 所以無(wú)法訪問(wèn) this]
枚冗。
3、類中的常量需要使用static const
聲明蛇损。
4赁温、靜態(tài)變量對(duì)于類級(jí)別的狀態(tài)是非常有用的。
5州藕、靜態(tài)變量在第一次使用的時(shí)候才被初始化束世。
6、靜態(tài)函數(shù)還可以當(dāng)做編譯時(shí)常量使用床玻。例如毁涉,你可以把靜態(tài)函數(shù)當(dāng)做常量構(gòu)造函數(shù)的參數(shù)來(lái)使用。
注意:對(duì)于通用的或者經(jīng)常使用的靜態(tài)函數(shù)锈死,考慮使用頂級(jí)方法而不是靜態(tài)函數(shù)贫堰。
-
示例
class Page {
int x;
static int currentPage = 1;
static void upPage() {
currentPage++;
print("up--> currentPage = $currentPage");
}
static void downPage() {
//報(bào)錯(cuò):Invalid reference to 'this' expression.
//print(this.x); //不能訪問(wèn)非靜態(tài)成員
currentPage--;
print("down--> currentPage = $currentPage");
}
}
void main() {
//1
print(Page.currentPage);
//up--> currentPage = 2
Page.upPage();
//down--> currentPage = 1
Page.downPage();
}
抽象函數(shù)
詳見(jiàn)抽象類
-
對(duì)象call方法(可調(diào)用的類)
- 說(shuō)明:
1、如果 Dart 類實(shí)現(xiàn)了 call()
函數(shù)待牵,則對(duì)象可以當(dāng)做方法來(lái)調(diào)用其屏。
2、只要方法名為call
缨该,無(wú)論有無(wú)參數(shù)偎行、有無(wú)返回值,都是可以的
- 示例:
class Person {
String name;
int age;
void call() {
print("name:$name;age:$age");
}
}
class Student {
String name;
int age;
void call(String name, int age) {
print("name:$name蛤袒;age:$age");
}
}
class Worker {
String name;
int age;
String call(String name, int age) {
return "name:$name熄云;age:$age";
}
}
void main() {
Person person = Person();
//name:null;age:null
person(); //因?yàn)閷?shí)現(xiàn)了call方法妙真,直接調(diào)用即可
Student student = Student();
//name:學(xué)生缴允;age:15
student("學(xué)生", 15);
Worker worker = new Worker();
String info = worker("工人", 33);
//work==>name:工人;age:33
print("work==>$info");
}
mixin
的繼承機(jī)制大审。calss
聲明一個(gè)類new
創(chuàng)建一個(gè)對(duì)象酷愧,new
可以省略。 class Person {
}
void main() {
Person p = new Person();
//省略new關(guān)鍵字
Person pp = Person();
}
定義:
1、定義一個(gè)和類名字一樣的方法就定義了一個(gè)構(gòu)造函數(shù)管引。
2士败、還可以帶有其他可選的標(biāo)識(shí)符,形如ClassName.identifier
褥伴。
class Person {
Person() {
print("person===super");
}
}
class Student extends Person { //這里是繼承父類谅将,后面會(huì)總結(jié)
Student() {
print("student====this");
}
}
void main() {
Student s = Student();
//打印結(jié)果:
//person===super
//student====this
}
默認(rèn)構(gòu)造函數(shù)
1、如果未顯式定義構(gòu)造函數(shù)重慢,會(huì)默認(rèn)一個(gè)空的構(gòu)造函數(shù)饥臂。
2、默認(rèn)構(gòu)造函數(shù)沒(méi)有參數(shù)似踱,并且會(huì)調(diào)用超類的沒(méi)有參數(shù)的構(gòu)造函數(shù)隅熙。
class Person {
Person() {
print("person===super");
}
}
class Student extends Person { //這里是繼承父類,后面會(huì)總結(jié)
}
void main() {
Student s = Student();
//打印結(jié)果:
//person===super
}
自定義構(gòu)造函數(shù)
1核芽、如果存在自定義構(gòu)造函數(shù)囚戚,則默認(rèn)構(gòu)造函數(shù)無(wú)效,即只能存在一個(gè)構(gòu)造函數(shù)(這也驗(yàn)證了函數(shù)不能重載的特性)轧简。
2驰坊、其中this
關(guān)鍵字指當(dāng)前的實(shí)例。
class Person {
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
//報(bào)錯(cuò):The default constructor is already defined.
Person() {
print("person===super");
}
}
語(yǔ)法糖
1哮独、由于把構(gòu)造函數(shù)參數(shù)賦值給實(shí)例變量的場(chǎng)景太常見(jiàn)了庐橙, Dart 提供了一個(gè)語(yǔ)法糖來(lái)簡(jiǎn)化這個(gè)操作:
class Person {
String name;
int age;
/*
//常規(guī)寫(xiě)法
Person(String name, int age) {
this.name = name;
this.age = age;
}*/
//語(yǔ)法糖寫(xiě)法
Person(this.name, this.age);
}
命名構(gòu)造函數(shù)
- 說(shuō)明:
1假勿、使用命名構(gòu)造函數(shù)可以為一個(gè)類實(shí)現(xiàn)多個(gè)構(gòu)造函數(shù)
2、使用命名構(gòu)造函數(shù)來(lái)更清晰的表明你的意圖
3态鳖、構(gòu)造函數(shù)不能繼承,所以超類的命名構(gòu)造函數(shù)也不會(huì)被繼承恶导。 - 實(shí)現(xiàn)方式:
類名.方法
浆竭。其中方法名稱可以自定義 - 示例:
class Person { String name; int age; //語(yǔ)法糖寫(xiě)法 Person(this.name, this.age); //fromName名稱可以隨便起名 Person.fromName(String name) { this.name = name; } //withAge名稱可以隨便起名 Person.withAge(int age) { this.age = age; } void printArgs() { print("name:$name;age:$age"); } } void main() { Person p = Person("張三", 18); //name:張三惨寿;age:18 p.printArgs(); Person pp = Person.fromName("李四"); //name:李四邦泄;age:null pp.printArgs(); Person ppp = Person.withAge(33); //name:null;age:33 ppp.printArgs(); }
常量構(gòu)造函數(shù)
- 說(shuō)明:
1裂垦、使用常量構(gòu)造函數(shù)可以創(chuàng)建編譯時(shí)常量顺囊,即類是不可變狀態(tài)。
2蕉拢、使用const
聲明構(gòu)造方法特碳,并且所有變量都為final
。
3晕换、要使用常量構(gòu)造函數(shù)只需要用 const 替代 new 即可午乓,也可以省略const
。
4闸准、兩個(gè)一樣的編譯時(shí)常量其實(shí)是 同一個(gè)對(duì)象(通過(guò)identical
可進(jìn)行對(duì)比)益愈。 - 示例:
class Person { final String name; final int age; const Person(this.name, this.age); void printArgs() { print("name:$name;age:$age"); } } void main() { const p = const Person("張三", 33); const pp = const Person("張三", 33); //true print(identical(p, pp)); //比較兩個(gè)對(duì)象是否相等 }
工廠構(gòu)造函數(shù)
- 說(shuō)明:
1夷家、如果一個(gè)構(gòu)造函數(shù)并不總是返回一個(gè)新的對(duì)象蒸其,則可以將其定義為工廠構(gòu)造函數(shù)。
2库快、工廠構(gòu)造函數(shù)摸袁,類似于設(shè)計(jì)模式中的工廠模式。
3缺谴、在構(gòu)造方法前添加關(guān)鍵字factory
實(shí)現(xiàn)一個(gè)工廠構(gòu)造方法但惶。
4、在工廠構(gòu)造方法中可以返回對(duì)象湿蛔。 - 注意:工廠構(gòu)造函數(shù)無(wú)法訪問(wèn)
this
膀曾。 - 示例:
下面代碼演示工廠構(gòu)造函數(shù) 如何從緩存中返回對(duì)象。
調(diào)用:class Logger { final String name; bool mute = false; // _cache 是個(gè)庫(kù)私有變量阳啥,在變量名前加`_`即為私有成員變量 static final Map<String, Logger> _cache = <String, Logger>{}; //添加 factory 定義為工廠構(gòu)造函數(shù) factory Logger(String name) { //如果緩存中有name添谊,則取出返回,若不存在則添加并返回察迟。 if (_cache.containsKey(name)) { return _cache[name]; } else { final logger = new Logger._internal(name); _cache[name] = logger; return logger; } } Logger._internal(this.name); void log(String msg) { if (!mute) { print(msg); } } }
var logger = new Logger('UI'); logger.log('Button clicked');
重定向構(gòu)造函數(shù)
- 說(shuō)明:
1斩狱、有時(shí)候一個(gè)構(gòu)造函數(shù)會(huì)調(diào)動(dòng)類中的其他構(gòu)造函數(shù)耳高,則可以通過(guò)重定向構(gòu)造函數(shù)。
2所踊、一個(gè)重定向構(gòu)造函數(shù)是沒(méi)有代碼的泌枪,在構(gòu)造函數(shù)聲明后,使用:
調(diào)用其他構(gòu)造函數(shù)秕岛。 - 示例:
class Person { String name; int age; //語(yǔ)法糖寫(xiě)法 Person(this.name, this.age); Person.formAge(int age): this("張三", age); //此種寫(xiě)法沒(méi)有給任何變量賦值碌燕,在調(diào)用后,name和age都為null Person.initParams(String name, int age); void printArgs() { print("name:$name继薛;age:$age"); } }
初始化列表
- 說(shuō)明:
1修壕、在構(gòu)造函數(shù)體執(zhí)行之前除了可以調(diào)用超類構(gòu)造函數(shù)之外,還可以初始化實(shí)例參數(shù)遏考。即初始化列表會(huì)在構(gòu)造方法體執(zhí)行前執(zhí)行慈鸠。
2、使用:
設(shè)置初始化表達(dá)式灌具,使用,
分隔初始化表達(dá)式青团。
3、初始化列表常用于設(shè)置final
變量的值稽亏。
官網(wǎng)警告: 初始化表達(dá)式等號(hào)右邊的部分不能訪問(wèn)this
壶冒。(本人驗(yàn)證,似乎并非如此截歉。) - 示例:
官網(wǎng)示例:
本地測(cè)試:class Point { num x; num y; Point(this.x, this.y); // Initializer list sets instance variables before // the constructor body runs. Point.fromJson(Map jsonMap) : x = jsonMap['x'], y = jsonMap['y'] { print('In Point.fromJson(): ($x, $y)'); } }
/** * person */ class Person { String name; int age; bool isMan; //初始化列表胖腾,加上了this Person(name, age): this.name = name, this.age = age; //初始化列表,加上了this Person.withMap(Map map): this.isMan = map["isMan"] { this.name = map["name"]; this.age = map["age"]; } void printArgs() { print("name:$name瘪松;age:$age"); } } /** * main */ import 'person.dart'; void main() { Person p = new Person("張三", 33); //name:張三咸作;age:33;isMan:null p.printArgs(); Person pp = Person.withMap({ "name": "李四", "age": 23, "isMan": true}); //name:李四宵睦;age:23记罚;isMan:true pp.printArgs(); }
注:
本人在測(cè)試的時(shí)候,在初始化列表上的變量加上了this
關(guān)鍵字壳嚎,編譯并未報(bào)錯(cuò)桐智,也可以正常執(zhí)行輸出結(jié)果。
這個(gè)地方不知是否是我的姿勢(shì)有誤烟馅,還是說(shuō)確實(shí)可以如此使用说庭,希望有知道的盆友可以解答我的困惑,非常感謝郑趁。
不過(guò)刊驴,一切以官方為準(zhǔn),最好不要加上this
- 設(shè)置
final
變量:import 'dart:math'; class Point { final num x; final num y; final num distanceFromOrigin; Point(x, y) : x = x, y = y, distanceFromOrigin = sqrt(x * x + y * y); } main() { var p = new Point(2, 3); print(p.distanceFromOrigin); }
說(shuō)明:
1捆憎、對(duì)象的成員包括方法和數(shù)據(jù) (函數(shù) 和 實(shí)例變量)舅柜。
2、當(dāng)你調(diào)用一個(gè)函數(shù)的時(shí)候躲惰,你是在一個(gè)對(duì)象上 調(diào)用:函數(shù)需要訪問(wèn)對(duì)象的方法 和數(shù)據(jù)致份。
3、所有沒(méi)有初始化的變量值都是 null础拨。
4知举、函數(shù)不能被重載,可以被子類覆寫(xiě)太伊。
調(diào)用:
- 使用點(diǎn)
.
來(lái)引用對(duì)象的變量或者方法。 - 使用
?.
來(lái)替代.
可以避免當(dāng)左邊對(duì)象為null
時(shí)候 拋出異常:
class Person {
//定義實(shí)例變量
String name;
int age;
//定義實(shí)例函數(shù)
void printArgs() {
print("name:${name}逛钻;age:${age}");
}
//演示方法不能被重載
//編譯錯(cuò)誤:The name 'printArgs' is already defined.
void printArgs(int age) {
print("name:${name}僚焦;age:${age}");
}
}
void main() {
Person p = new Person();
p.name = "張三";
p.age = 33;
//name:張三;age:33
p.printArgs();
Person pp;
pp?.name = "李四";
//報(bào)錯(cuò):Unhandled exception:
//NoSuchMethodError: The setter 'age=' was called on null.
//Receiver: null
//Tried calling: age=23
pp.age = 23;
}
實(shí)例變量
- 說(shuō)明:
1曙痘、所有沒(méi)有初始化的變量值都是 null芳悲。
2剧浸、每個(gè)實(shí)例變量都會(huì)自動(dòng)生成一個(gè)getter
方法(隱含的)彼硫。
3祠够、非final
變量會(huì)自動(dòng)生成一個(gè)setter
方法(隱含的)叽掘。
4殿漠、如果你在實(shí)例變量定義的時(shí)候初始化該變量(不是 在構(gòu)造函數(shù)或者其他方法中初始化)雇庙,該值是在實(shí)例創(chuàng)建的時(shí)候 初始化的掖鱼,也就是在構(gòu)造函數(shù)和初始化參數(shù)列 表執(zhí)行之前帮寻。 - 示例:
class Point { num x; num y; } main() { var point = new Point(); point.x = 4; // 調(diào)用x旺订,是用了setter方法 assert(point.x == 4); // 調(diào)用x弄企,是用了getter方法 assert(point.y == null); // 變量默認(rèn)是null }
實(shí)例函數(shù)
- 說(shuō)明
1、函數(shù)是類中定義的方法区拳,是類對(duì)象的行為拘领。
2、對(duì)象的實(shí)例函數(shù)可以訪問(wèn)this
樱调。 - 示例
import 'dart:math'; class Point { num x; num 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); } }
計(jì)算屬性-Getters And Setters
說(shuō)明
1约素、Getters 和 setters 是用來(lái)設(shè)置和訪問(wèn)對(duì)象屬性的特殊函數(shù)。
2笆凌、每個(gè)實(shí)例變量都隱含的具有一個(gè)getter
圣猎, 如果變量不是final
的則還有一個(gè)setter
。
3菩颖、你可以通過(guò)實(shí)行getter
和setter
來(lái)創(chuàng)建新的屬性样漆, 使用get
和set
關(guān)鍵字定義getter
和setter
。
4晦闰、計(jì)算屬性的值是通過(guò)計(jì)算而來(lái)放祟,本身不存儲(chǔ)值鳍怨。
5、計(jì)算屬性賦值跪妥,其實(shí)是通過(guò)計(jì)算轉(zhuǎn)換到其他實(shí)例變量鞋喇。
6、在開(kāi)始使用實(shí)例變量眉撵,后來(lái)可以把實(shí)例變量用函數(shù)包裹起來(lái)侦香,而調(diào)用你代碼的地方不需要修改。官網(wǎng)注意(本人此處還未搞明白什么意思)
1纽疟、像 (++
) 這種操作符不管是否定義getter
都會(huì)正確的執(zhí)行罐韩。 為了避免其他副作用, 操作符只調(diào)用getter
一次污朽,然后把其值保存到一個(gè)臨時(shí)變量中散吵。-
示例
class Rectangle { num left; num top; num width; num height; Rectangle(this.left, this.top, this.width, this.height); // 定義兩個(gè)計(jì)算屬性: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; } main() { var rect = new Rectangle(3, 4, 20, 15); assert(rect.left == 3); rect.right = 12; assert(rect.left == -8); }
類變量和類函數(shù)(靜態(tài)成員)
-
說(shuō)明
1、使用static
關(guān)鍵字來(lái)實(shí)現(xiàn)類級(jí)別的變量和函數(shù)
2蟆肆、靜態(tài)成員不能訪問(wèn)非靜態(tài)成員(this調(diào)用)矾睦,非靜態(tài)成員可以訪問(wèn)靜態(tài)成員。
[
靜態(tài)函數(shù)不再類實(shí)例上執(zhí)行炎功, 所以無(wú)法訪問(wèn) this]
枚冗。
3、類中的常量需要使用static const
聲明蛇损。4赁温、靜態(tài)變量對(duì)于類級(jí)別的狀態(tài)是非常有用的。
5州藕、靜態(tài)變量在第一次使用的時(shí)候才被初始化束世。
6、靜態(tài)函數(shù)還可以當(dāng)做編譯時(shí)常量使用床玻。例如毁涉,你可以把靜態(tài)函數(shù)當(dāng)做常量構(gòu)造函數(shù)的參數(shù)來(lái)使用。
注意:對(duì)于通用的或者經(jīng)常使用的靜態(tài)函數(shù)锈死,考慮使用頂級(jí)方法而不是靜態(tài)函數(shù)贫堰。 -
示例
class Page { int x; static int currentPage = 1; static void upPage() { currentPage++; print("up--> currentPage = $currentPage"); } static void downPage() { //報(bào)錯(cuò):Invalid reference to 'this' expression. //print(this.x); //不能訪問(wèn)非靜態(tài)成員 currentPage--; print("down--> currentPage = $currentPage"); } } void main() { //1 print(Page.currentPage); //up--> currentPage = 2 Page.upPage(); //down--> currentPage = 1 Page.downPage(); }
抽象函數(shù)
詳見(jiàn)抽象類
對(duì)象call方法(可調(diào)用的類)
- 說(shuō)明:
1、如果 Dart 類實(shí)現(xiàn)了call()
函數(shù)待牵,則對(duì)象可以當(dāng)做方法來(lái)調(diào)用其屏。
2、只要方法名為call
缨该,無(wú)論有無(wú)參數(shù)偎行、有無(wú)返回值,都是可以的 - 示例:
class Person { String name; int age; void call() { print("name:$name;age:$age"); } } class Student { String name; int age; void call(String name, int age) { print("name:$name蛤袒;age:$age"); } } class Worker { String name; int age; String call(String name, int age) { return "name:$name熄云;age:$age"; } } void main() { Person person = Person(); //name:null;age:null person(); //因?yàn)閷?shí)現(xiàn)了call方法妙真,直接調(diào)用即可 Student student = Student(); //name:學(xué)生缴允;age:15 student("學(xué)生", 15); Worker worker = new Worker(); String info = worker("工人", 33); //work==>name:工人;age:33 print("work==>$info"); }
更多相關(guān)信息: Emulating Functions in Dart(在 Dart 中模擬方法)
4珍德、繼承與多態(tài)
-
定義
1练般、使用關(guān)鍵字extends
繼承一個(gè)類
2、子類會(huì)繼承父類可見(jiàn)的屬性和方法(可以用@override
注解來(lái)表明為覆寫(xiě)方法)锈候,不會(huì)繼承構(gòu)造方法
3薄料、子類能夠覆寫(xiě)父類的方法、getter
和setter
4泵琳、Dart具有單繼承都办、多態(tài)性
5、Dart的多態(tài)性可以讓子類實(shí)例指向父類的變量虑稼。- 示例
class Person { String name; int age; void work() { print("person--->working..."); } bool get isAdult => age > 18; void printArgs() { print("person==>name:$name;age:$age势木;isAdult:$isAdult"); } } class Student extends Person { Student() { } Student.initParams(String name, int age) { this.name = name; this.age = age; } void study() { print("student--->studying..."); } @override bool get isAdult => age > 15; @override void printArgs() { //super.printArgs(); print("student==>name:$name蛛倦;age:$age;isAdult:$isAdult"); } } void main() { Student student = Student(); student.name = "張三"; student.age = 16; //person--->working... student.work(); //student==>name:張三啦桌;age:16溯壶;isAdult:true student.printArgs(); //多態(tài)調(diào)用 Person p = Student.initParams("李四", 17); //student==>name:李四;age:17甫男;isAdult:true p.printArgs(); if (p is Student) { //student--->studying... p.study(); } }
- 示例
-
繼承中的構(gòu)造函數(shù)
1且改、子類的構(gòu)造方法默認(rèn)會(huì)調(diào)用父類的無(wú)名無(wú)參構(gòu)造函數(shù)。
2板驳、如果父類沒(méi)有無(wú)名無(wú)參的構(gòu)造函數(shù)又跛,則需要顯式調(diào)用父類構(gòu)造函數(shù)。
3若治、在構(gòu)造方法參數(shù)后使用:
顯式調(diào)用父類構(gòu)造函數(shù)慨蓝。
4、如果有初始化列表端幼,初始化列表要放在父類構(gòu)造函數(shù)之前礼烈。注:子類不能使用
重定向構(gòu)造函數(shù)
(無(wú)方法體的:
設(shè)置變量的構(gòu)造函數(shù))進(jìn)行自定義函數(shù)。本人認(rèn)為:因?yàn)槌跏蓟瘏?shù)要提前于父類構(gòu)造函數(shù)婆跑,這個(gè)時(shí)候還不能使用this
(待驗(yàn)證)此熬。- 示例
class Person { String name; int age; /* #1 Person() { print("person==="); } */ Person(this.name); Person.initParams(this.name, this.age); } class Student extends Person { //第一種 Student(String name) : super(name); //第二種 Student.initParams(String name, int age) : super.initParams(name, age); // 無(wú)法創(chuàng)建 // Student.initParams(String name, int age):this.name = name; } void main() { //#1 //打印:person=== //Student student = Student(); }
初始化列表:
class Person { String name; int age; Person(this.name); Person.initParams(this.name, this.age); } class Student extends Person { final bool isMan; Student.withParams(String name, int age, bool man) : isMan = man, super.initParams(name, age); } ```
-
構(gòu)造方法執(zhí)行順序
1、父類的構(gòu)造函數(shù)在子類構(gòu)造函數(shù)的方法體開(kāi)始執(zhí)行的位置調(diào)用犀忱。
2募谎、如果有初始化列表,初始化列表會(huì)在父類構(gòu)造函數(shù)之前執(zhí)行峡碉。- 示例:
class Person { String name; int age; Person(this.name); Person.initParams(this.name, this.age) { print("Person.initParams===="); } } class Student extends Person { final bool isMan; Student.withParams(String name, int age, bool man) : isMan = getMan(man), super.initParams(name, age) { print("Student.withParams===="); } static bool getMan(man) { print("Student===man:$man"); return man; } } void main() { Student student = Student.withParams("學(xué)生", 17, true); /** * 打印如下: Student===man:true Person.initParams==== Student.withParams==== */ }
- 示例:
-
擴(kuò)展:
查看所有超類Object
近哟,其中有一些成員的前面用關(guān)鍵字external
來(lái)修飾,它的作用是根據(jù)不同平臺(tái)(Dart是跨平臺(tái)的語(yǔ)言)語(yǔ)言而有不同的具體實(shí)現(xiàn)鲫寄。/** * Returns a string representation of this object. */ external String toString();
5吉执、抽象類
定義
1、抽象類是一個(gè)不能被實(shí)例化的類地来。
2戳玫、使用abstract
修飾符定義一個(gè) 抽象類。-
說(shuō)明:
1未斑、抽象類通常用來(lái)定義接口咕宿, 以及部分實(shí)現(xiàn)。
2蜡秽、如果你希望你的抽象類是可實(shí)例化的府阀,則定義一個(gè) 工廠構(gòu)造函數(shù)。
3芽突、抽象類通常具有 抽象函數(shù)试浙。
4、抽象類不能直接被實(shí)例化寞蚌。
5田巴、抽象類可以沒(méi)有抽象方法。
6挟秤、有抽象方法的類一定要聲明為抽象類壹哺。-
示例
abstract class Person { void run(); void printArgs() { print("person==="); } } class Student extends Person { @override void run() { print("student run..."); } } void main() { Person p = new Student(); //student run... p.run(); }
注意:
官網(wǎng)說(shuō)明:下面的類(示例)不是抽象的,但是定義了一個(gè)抽象函數(shù)艘刚,這樣的類是可以被實(shí)例化的管宵。
但經(jīng)過(guò)測(cè)試,確實(shí)是有警告攀甚,運(yùn)行也會(huì)報(bào)錯(cuò)啄糙,不太明白這里所說(shuō)的可以被實(shí)例化
是什么意思。
// This class is declared abstract and thus // can't be instantiated. abstract class AbstractContainer { // ...Define constructors, fields, methods... void updateChildren(); // Abstract method. } class SpecializedContainer extends AbstractContainer { // ...Define more constructors, fields, methods... void updateChildren() { // ...Implement updateChildren()... } // Abstract method causes a warning but // doesn't prevent instantiation. void doSomething(); }
-
-
抽象函數(shù)
- 抽象方法不用
abstract
修飾云稚,沒(méi)有方法體實(shí)現(xiàn)隧饼。 - 實(shí)例函數(shù)、 getter静陈、和 setter 函數(shù)可以為抽象函數(shù)燕雁。
- 抽象函數(shù)是只定義函數(shù)接口但是沒(méi)有實(shí)現(xiàn)的函數(shù)诞丽,由子類來(lái)實(shí)現(xiàn)該函數(shù)。如果用分號(hào)來(lái)替代函數(shù)體則這個(gè)函數(shù)就是抽象函數(shù)拐格。
- 調(diào)用一個(gè)沒(méi)實(shí)現(xiàn)的抽象函數(shù)會(huì)導(dǎo)致運(yùn)行時(shí)異常僧免。
- 抽象方法不用
6、接口
- 定義
一個(gè)類通過(guò)使用關(guān)鍵字implements
來(lái)實(shí)現(xiàn)一個(gè)或者多個(gè)接口捏浊。 - 說(shuō)明
1懂衩、類和接口是統(tǒng)一的,類就是接口金踪。
2浊洞、一個(gè)類實(shí)現(xiàn)了某個(gè)接口,就要實(shí)現(xiàn)此接口的每個(gè)成員胡岔。
3法希、如果是復(fù)用已有類的接口,使用繼承(extends)靶瘸。
4苫亦、如果只是使用已有類的外在行為,使用接口(implements)怨咪。
5屋剑、每個(gè)類都隱式的定義了一個(gè)包含所有實(shí)例成員的接口 - 示例:
class Person { String name; int get age => 18; void run() { print("run..."); } } class Student implements Person { @override String name; @override // TODO: implement age int get age => 15; @override void run() { print("student run..."); } } void main() { Student student = Student(); student.run(); }
- 建議:
1、將抽象類作為接口使用诗眨,讓子類來(lái)實(shí)現(xiàn)(因?yàn)轭惣唇涌诒穑钥梢酝ㄟ^(guò)關(guān)鍵字implements
來(lái)實(shí)現(xiàn))。
示例:abstract class Person { void run(); } class Student implements Person { String name; int get age => 15; @override void run() { print("student run..."); } } void main() { Student student = Student(); //student run... student.run(); }
7辽话、枚舉類
定義
使用關(guān)鍵字enum
來(lái)定義一個(gè)枚舉類型。說(shuō)明
1卫病、枚舉類型通常稱之為enumerations
或者enums
油啤,是一種特殊的類,用來(lái)表現(xiàn)一個(gè)固定數(shù)目的常量蟀苛。
2益咬、枚舉是一種有窮序列集的數(shù)據(jù)類型。
3帜平、常用于代替常量幽告,控制語(yǔ)句等。特性
1裆甩、枚舉中的index
屬性從0開(kāi)始冗锁,依次累加。
2嗤栓、枚舉中的values
屬性可以列舉出所有的枚舉值冻河。x
3箍邮、無(wú)法顯示的初始化一個(gè)枚舉類型,即不能指定原始值(給枚舉常量賦值)叨叙。
4锭弊、無(wú)法繼承枚舉類型、無(wú)法使用 mixin擂错、無(wú)法實(shí)現(xiàn)一個(gè)枚舉類型味滞。-
示例:
enum Color { red, green, blue, //報(bào)錯(cuò),不能指定原始值 //white = "#FFFFFF", } void main() { var color = Color.red; switch(color) { case Color.red: print("紅色"); break; case Color.blue: print("藍(lán)色"); break; case Color.green: print("綠色"); break; } //紅色 //index==> 0 print("index==> ${color.index}"); List<Color> values = Color.values; //[Color.red, Color.green, Color.blue] print(values); }
8钮呀、Mixins
定義
使用 with 關(guān)鍵字后面為一個(gè)或者多個(gè) mixin 名字來(lái)使用 mixin剑鞍。說(shuō)明
1、Mixins 類似于多繼承行楞,實(shí)在多類繼承中重用一個(gè)類代碼的方式攒暇。
2、作為Mixin的類不能顯示聲明構(gòu)造函數(shù)子房,不能調(diào)用 super 形用。(由于沿著繼承鏈傳遞構(gòu)造函數(shù)參數(shù)的需要,該約束能避免出現(xiàn)新的連鎖問(wèn)題证杭。)
3田度、作為Mixin的類只能繼承自Object
。-
示例
-
繼承示例:
class A { void a() { print("A.a..."); } } class B { void a() { print("B.a..."); } void b() { print("B.b..."); } } class C { void a() { print("C.a..."); } void b() { print("C.b..."); } void c() { print("C.c..."); } } class D extends A with B, C { } void main() { D d = D(); //C.a... d.a(); }
說(shuō)明:
這里打印了C.a...
是和繼承的順序有關(guān)的解愤,如果將D
類繼承B
和C
的順序互換镇饺,則會(huì)調(diào)用B
中的方法,打印結(jié)果為B.a...
送讲。 -
組合示例:
abstract class Engine { void work(); } class OilEngine implements Engine { @override void work() { print("Work with oil..."); } } class ElectricEngine implements Engine { @override void work() { print("Work with electric..."); } } class Tyre { String name; void run() {} } class Car = Tyre with ElectricEngine; class Bus = Tyre with OilEngine;
說(shuō)明:
這種方式一般可以實(shí)現(xiàn)模塊的組裝奸笤,將自己需要的模塊進(jìn)行組合,實(shí)現(xiàn)不同的功能哼鬓。
-
-
官網(wǎng)說(shuō)明:
從 Dart 1.13 開(kāi)始监右, 這兩個(gè)限制在 Dart VM 上 沒(méi)有那么嚴(yán)格了:- Mixins 可以繼承其他類,不再限制為繼承
Object
异希。 - Mixins 可以調(diào)用
super()
健盒。
- Mixins 可以繼承其他類,不再限制為繼承
9、操作符
- 對(duì)象操作符
-
?.
:條件成員訪問(wèn)
as
:類型轉(zhuǎn)換
is
:判斷是指定類型
is!
:判斷非指定類型
..
:級(jí)聯(lián)操作称簿,即可連續(xù)調(diào)用對(duì)象成員扣癣,因?yàn)闀?huì)返回當(dāng)前對(duì)象。 - 示例
class Person { String name; int age; void work() { print("person--->name:$name憨降;age:$age"); } } void main() { var p; p = ""; p = new Person(); //不會(huì)報(bào)錯(cuò) p?.age = 43; p.name = "張三"; p.age = 43; //person--->name:張三父虑;age:43 (p as Person).work(); if (p is Person) { //person--->name:張三;age:43 p.work(); } Person person = Person(); person..name = "Tom" ..age = 33 ..work(); //person--->name:Tom授药;age:33 }
-
- 操作符覆寫(xiě)
- 說(shuō)明:
1频轿、操作符的覆寫(xiě)需要在類中定義垂涯。
2、如果覆寫(xiě)了==
航邢,則還應(yīng)該覆寫(xiě)對(duì)象的hashCode
和getter
函數(shù)耕赘。 關(guān)于 覆寫(xiě)==
和hashCode
的示例請(qǐng)參考 實(shí)現(xiàn) map 的 keys。 - 可覆寫(xiě)操作符
< + | [] > / ^ []= <= ~/ & ~ >= * << == – % >> - 格式:
class Xxx { 返回類型 operator 操作符(參數(shù)1, 參數(shù)2, 參數(shù)....) { 方法體 return 返回值; } }
- 示例:
class Person { int age; Person(this.age); bool operator >(Person p) { return this.age > p.age; } int operator [](String ageParam) { if("age"==ageParam) { return this.age; } else { return 0; } } /** * 以下兩個(gè)覆寫(xiě)方法膳殷,可以通過(guò)右鍵選擇'Generate...' * 然后點(diǎn)擊選擇'== and hashCode'直接生成 */ @override bool operator ==(Object other) => identical(this, other) || other is Person && runtimeType == other.runtimeType && age == other.age; @override int get hashCode => age.hashCode; } void main() { Person p1 = Person(22); Person p2 = Person(33); //p1>p2? ==> false print("p1>p2? ==> ${p1>p2}"); //p1.age==> 22 print("p1.age==> ${p1["age"]}"); }
- 說(shuō)明:
七操骡、泛型
1、定義
方式
1赚窃、使用<…>
來(lái)聲明泛型
2册招、通常情況下,使用一個(gè)字母來(lái)代表類型參數(shù)勒极, 例如E
,T
,S
,K
, 和V
等是掰。
3、List
是一個(gè) 泛型 (或者 參數(shù)化) 類型辱匿,定義為List<E>
键痛。使用泛型的原因
1、在 Dart 中類型是可選的匾七,可以通過(guò)泛型來(lái)限定類型絮短。
2、使用泛型可以有效地減少重復(fù)的代碼昨忆。 泛型可以在多種類型之間定義同一個(gè)實(shí)現(xiàn)丁频,同時(shí)還可以繼續(xù)使用檢查模式和靜態(tài)分析工具提供的代碼分析功能。
3邑贴、如果你需要更加安全的類型檢查席里,則可以使用 參數(shù)化定義。
2拢驾、用法
-
類的泛型
- 說(shuō)明:
在調(diào)用構(gòu)造函數(shù)的時(shí)候奖磁, 在類名字后面使用尖括號(hào)(<...>
)來(lái)指定 泛型類型。 - 示例:
class Cache<T> { T value; T get() { return value; } void put(T value) { this.value = value; } } void main() { Cache<String> cacheStr = Cache(); cacheStr.put("張三"); //張三 print(cacheStr.get()); Cache<int> cacheNum = Cache(); cacheNum.put(333); //333 print(cacheNum.get()); }
- 說(shuō)明:
-
函數(shù)的泛型
- 說(shuō)明:
在函數(shù)上使用泛型独旷,可以在如下地方使用類型參數(shù)(具體見(jiàn)示例):
1、函數(shù)的返回值類型 (T)寥裂。
2嵌洼、參數(shù)的類型 (T value).
3、局部變量的類型 (T temp).
注意: 版本說(shuō)明: 在 Dart SDK 1.21. 開(kāi)始可以使用泛型函數(shù)封恰。
- 示例:
class Util { static T put<T>(T value) { T temp; if (value!=null) { temp = value; } print("temp = $temp"); return value; } } void main() { //張三 String value = Util.put<String>("張三"); //報(bào)錯(cuò)麻养,提示類型錯(cuò)誤 Util.put<String>(1); }
- 說(shuō)明:
3、限制泛型類型
- 說(shuō)明
當(dāng)需要對(duì)泛型的具體類型進(jìn)行限定的時(shí)候诺舔,可以使用extends
關(guān)鍵字來(lái)限定泛型參數(shù)的具體類型鳖昌。 - 示例:
// T must be SomeBaseClass or one of its descendants. class Foo<T extends SomeBaseClass> {...} class Extender extends SomeBaseClass {...} void main() { // It's OK to use SomeBaseClass or any of its subclasses inside <>. var someBaseClassFoo = new Foo<SomeBaseClass>(); var extenderFoo = new Foo<Extender>(); // It's also OK to use no <> at all. var foo = new Foo(); // Specifying any non-SomeBaseClass type results in a warning and, in // checked mode, a runtime error. // var objectFoo = new Foo<Object>(); }
八备畦、庫(kù)和可見(jiàn)性
1、簡(jiǎn)介
- Dart中的可見(jiàn)性以
library
為單位 - 默認(rèn)情況下许昨,每一個(gè)Dart文件就是一個(gè)庫(kù)
- 使用
_
表示庫(kù)的私有性懂盐。 - 使用
import
關(guān)鍵字導(dǎo)入庫(kù)
2、示例:
-
person.dart
/** * peerson */ class Person { String name; int age; Person(name, age): this.name = name, this.age = age; void printArgs() { print("name:$name糕档;age:$age"); } }
-
main
import 'person.dart'; void main() { Person p = new Person("張三", 33); //name:張三莉恼;age:33 p.printArgs(); }
九、異常
1速那、簡(jiǎn)介
- 代碼中可以出現(xiàn)異常和捕獲異常俐银。
- 異常表示一些未知的錯(cuò)誤情況。
- 如果異常沒(méi)有捕獲端仰,則異常會(huì)拋出捶惜,導(dǎo)致拋出異常的代碼終止執(zhí)行。
- 和 Java 不同的是荔烧,所有的 Dart 異常是非檢查異常吱七。
- 方法不一定聲明了他們所拋出的異常, 并且你不要求捕獲任何異常茴晋。
詳情請(qǐng)參考 Exceptions 部分陪捷。
2、類型
注意:Dart 代碼可以拋出任何非null
對(duì)象為異常诺擅,不僅僅是實(shí)現(xiàn)了 Exception
或者 Error
的對(duì)象市袖。
3、Throw(拋出異常)
- 可以拋出任意對(duì)象:
throw 'Out of llamas!';
- 可以使用箭頭函數(shù)
=>
:
拋出異常是一個(gè)表達(dá)式烁涌,所以可以在 => 語(yǔ)句中使用苍碟,也可以在其他能使用表達(dá)式的地方拋出異常。distanceTo(Point other) => throw new UnimplementedError();
4撮执、Catch(捕獲異常)
異常捕獲的關(guān)鍵字
on
:捕獲異常微峰,指定異常類型
catch
:捕獲異常,捕獲異常對(duì)象抒钱。
rethrow
:重新拋出異常說(shuō)明:
1蜓肆、捕獲異常可以避免異常繼續(xù)傳遞(你重新拋出rethrow異常除外)谋币。捕獲異常給你一個(gè)處理該異常的機(jī)會(huì)仗扬。
2、對(duì)于可以拋出多種類型異常的代碼蕾额,你可以指定多個(gè)捕獲語(yǔ)句早芭。每個(gè)語(yǔ)句分別對(duì)應(yīng)一個(gè)異常類型,如果捕獲語(yǔ)句沒(méi)有指定異常類型诅蝶,則該可以捕獲任何異常類型退个。
3募壕、函數(shù)catch()
可以帶有一個(gè)或者兩個(gè)參數(shù),第一個(gè)參數(shù)為拋出的異常對(duì)象语盈,第二個(gè)為堆棧信息 (一個(gè) StackTrace 對(duì)象)舱馅。-
示例:
var foo = ''; void misbehave() { try { foo = "You can't change a final variable's value."; //此處演示異常 String sub = foo.substring(100); } on Exception catch (e) { print('Exception details:\n $e'); } catch (e, s) { print('misbehave() partially handled ${e.runtimeType}.'); print('Stack trace:\n$s'); rethrow; // Allow callers to see the exception. } } void main() { try { misbehave(); } catch (e) { print('main() finished handling ${e.runtimeType}.'); } } /** * 打印結(jié)果: misbehave() partially handled RangeError. Stack trace: #0 _StringBase.substring (dart:core/runtime/libstring_patch.dart:384:7) #1 misbehave (file:///Users/yu/Work/Workplace/Flutter/Dart/lesson2/exception_test.dart:7:26) #2 main (file:///Users/yu/Work/Workplace/Flutter/Dart/lesson2/exception_test.dart:19:9) #3 _startIsolate.<anonymous closure> (dart:isolate/runtime/libisolate_patch.dart:300:19) #4 _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:171:12) main() finished handling RangeError. */
5、Finally
要確保某些代碼執(zhí)行黎烈,不管有沒(méi)有出現(xiàn)異常都需要執(zhí)行习柠,可以使用 一個(gè)
finally
語(yǔ)句來(lái)實(shí)現(xiàn)。如果沒(méi)有
catch
語(yǔ)句來(lái)捕獲異常照棋,則在執(zhí)行完finally
語(yǔ)句后资溃,異常被拋出了。定義的
finally
語(yǔ)句在任何匹配的catch
語(yǔ)句之后執(zhí)行烈炭。-
示例:
try { String sub = "123".substring(10); } catch(e) { print('Exception details:\n$e'); } finally { print("result........"); }
十溶锭、元數(shù)據(jù)
1、簡(jiǎn)介:
- 使用元數(shù)據(jù)可以給你的代碼添加其他額外信息符隙。
- 元數(shù)據(jù)可以在
library
趴捅、class
、typedef
霹疫、type parameter
拱绑、constructor
、factory
丽蝎、function
猎拨、field
、parameter
屠阻、或者variable
聲明之前使用红省,也可以在import
或者export
指令之前使用。 - 使用反射可以在運(yùn)行時(shí)獲取元數(shù)據(jù) 信息国觉。
2吧恃、定義:
- 元數(shù)據(jù)注解是以
@
字符開(kāi)頭,后面是一個(gè)編譯時(shí)常量(例如deprecated
)麻诀。 - 調(diào)用一個(gè)常量構(gòu)造函數(shù)痕寓。
形如:@deprecated
,@override
3蝇闭、類型:
-
Dart內(nèi)置元數(shù)據(jù)注解:
@deprecated
@override
@proxy
class Television { /// _Deprecated: Use [turnOn] instead._ @deprecated void activate() { turnOn(); } /// Turns the TV's power on. void turnOn() { print('on!'); } }
-
自定義元數(shù)據(jù)注解:
library todo; class todo { final String who; final String what; const todo(this.who, this.what); }
使用 @todo 注解的示例:
import 'todo.dart'; @todo('seth', 'make this do something') void doSomething() { print('do something'); }