Dart 語(yǔ)法學(xué)習(xí)目錄
第一節(jié): Dart 語(yǔ)法了解,認(rèn)識(shí)變量,常量,數(shù)據(jù)類(lèi)型
第二節(jié): Dart 操作符(運(yùn)算符)
第三節(jié): Dart 中流程控制,條件判斷以及循環(huán)語(yǔ)句
第四節(jié): Dart 中常用集合 List/Map
第五節(jié): Dart 函數(shù)使用,聲明函數(shù)/匿名函數(shù)/可選參數(shù)/作用域/閉包
第六節(jié): Dart 面向?qū)ο?構(gòu)造函數(shù)/靜態(tài)屬性
第七節(jié): Dart中抽象類(lèi)abstract/接口implements/混入Mixin
第八節(jié): Dart中泛型/泛型定義與使用
第九節(jié): Dart 中的庫(kù)/自定義庫(kù)/內(nèi)置庫(kù)/第三方庫(kù)
1. Dart中的抽象類(lèi)和抽象方法
1.1 定義抽象類(lèi)
dart中的抽象類(lèi)主要用于定義標(biāo)準(zhǔn), 子類(lèi)可以繼承抽象類(lèi), 也可以實(shí)現(xiàn)抽象類(lèi)的接口
定義抽象類(lèi)
- 抽象類(lèi)通過(guò)abstract關(guān)鍵字類(lèi)定義
- 抽象類(lèi)不能被實(shí)例化
// 定義抽象類(lèi)
abstract class Animate{
}
// 入口函數(shù)
void main(){
// 實(shí)例化抽象類(lèi)就報(bào)錯(cuò)
var cat = new Animate();
}
1.2 抽象方法
抽象方法的定義
- Dart中沒(méi)有方法體的方法我們稱(chēng)為抽象方法:
- Dart中的抽象方法不能用abstract聲明,
示例
抽象類(lèi)中的抽象方法
// 定義抽象方法
abstract class Animate{
// 抽象方法
// 抽象方法不能使用abstract聲明
// 如果使用就會(huì)報(bào)錯(cuò)
void eat();
}
非抽象類(lèi)中定義抽象方法就會(huì)報(bào)錯(cuò),
class Dog{
// 屬性
String name = "哈士奇";
// 方法
void getInfo(){
print("我是${name}");
}
// 抽象方法
void sayHello(); // 報(bào)錯(cuò)
}
所以不要在非抽象類(lèi)中定義抽象方法
1.3 抽象類(lèi)的說(shuō)明
- 如果子類(lèi)繼承抽象類(lèi)必須的實(shí)現(xiàn)里面的抽象方法
- 如果抽象類(lèi)被當(dāng)做接口實(shí)現(xiàn)的話(huà), 子類(lèi)必須得實(shí)現(xiàn)抽象類(lèi)里面定義的所有屬性和方法
- 抽象類(lèi)不能被實(shí)例化,只有繼承它的子類(lèi)可以
- 抽象類(lèi)通常用來(lái)定義接口,
- 抽象類(lèi)通常具有 抽象方法
- 有抽象方法的類(lèi)一定要聲明為抽象類(lèi)。
使用示例
// 定義一個(gè)抽象類(lèi)
abstract class Animal{
// 抽象方法
eat();
}
// 子類(lèi)繼承抽象類(lèi)
class Dog extends Animal{
String name;
Dog(this.name){}
// 子類(lèi)必須實(shí)現(xiàn)抽象類(lèi)的方法
@override
eat() {
print("${this.name}喜歡吃骨頭");
}
}
// 子類(lèi)繼承抽象類(lèi)
class Cat extends Animal{
String name;
Cat(this.name){}
// 子類(lèi)必須實(shí)現(xiàn)抽象類(lèi)的方法
@override
eat() {
print("${this.name}喜歡吃千層餅");
}
}
void main(){
Dog dog = new Dog("哈士奇");
dog.eat(); // 哈士奇喜歡吃骨頭
Cat cat = new Cat("加菲貓");
cat.eat(); // 加菲貓喜歡吃千層餅
}
1.4 抽象類(lèi)也可以有非抽象方法
抽象類(lèi)里也可以定義非抽象方法, 這些方法都可以被子類(lèi)多調(diào)用
// 定義一個(gè)抽象類(lèi)
abstract class Animal{
// 抽象方法
eat();
// 非抽象方法
printInfo(){
print("我就是抽象類(lèi)里的一個(gè)非抽象方法");
}
}
// 子類(lèi)繼承抽象類(lèi)
class Dog extends Animal{
String name;
Dog(this.name){}
// 子類(lèi)必須實(shí)現(xiàn)抽象類(lèi)的方法
@override
eat() {
print("${this.name}喜歡吃骨頭");
}
}
// 子類(lèi)繼承抽象類(lèi)
class Cat extends Animal{
String name;
Cat(this.name){}
// 子類(lèi)必須實(shí)現(xiàn)抽象類(lèi)的方法
@override
eat() {
print("${this.name}喜歡吃千層餅");
}
}
void main(){
Dog dog = new Dog("哈士奇");
dog.eat(); // 哈士奇喜歡吃骨頭
// 子類(lèi)調(diào)用繼承的抽象類(lèi)中的非抽象方法
dog.printInfo(); // 我就是抽象類(lèi)里的一個(gè)非抽象方法
Cat cat = new Cat("加菲貓");
cat.eat(); // 加菲貓喜歡吃千層餅
dog.printInfo(); // 我就是抽象類(lèi)里的一個(gè)非抽象方法
}
2. 多態(tài)
2.1 正常使用的多態(tài)
多態(tài)就是父類(lèi)定義一個(gè)方法不去實(shí)現(xiàn),讓繼承他的子類(lèi)去實(shí)現(xiàn), 每個(gè)子類(lèi)有不同的表現(xiàn)
其實(shí)剛剛講的抽象類(lèi)的示例就是一個(gè)多態(tài), 父類(lèi)定義eat方法, 但是沒(méi)有實(shí)現(xiàn)他, 不同的子類(lèi)實(shí)現(xiàn)了eat方法的不同功能,這就是多態(tài)
2.2 子類(lèi)的實(shí)例賦值給父類(lèi)的引用
Dart 中的多態(tài) 講子類(lèi)類(lèi)型的指針賦值給父類(lèi)類(lèi)型的指針,同一個(gè)函數(shù)調(diào)用會(huì)有不同的執(zhí)行效果
// 定義一個(gè)抽象類(lèi)
abstract class Animal{
// 抽象方法
eat();
}
// 子類(lèi)繼承抽象類(lèi)
class Dog extends Animal{
String name;
Dog(this.name){}
// 子類(lèi)必須實(shí)現(xiàn)抽象類(lèi)的方法
@override
eat() {
print("${this.name}喜歡吃骨頭");
}
// 子類(lèi)自己的方法
run(){
print("${this.name}在愉快的奔跑");
}
}
void main(){
// 通過(guò)子類(lèi) 定義實(shí)例
// Dog dog = new Dog("哈士奇");
// dog.eat(); // 哈士奇喜歡吃骨頭
// dog.run(); // 哈士奇在愉快的奔跑
// 將子類(lèi)的實(shí)例賦值給了父類(lèi)的引用
Animal dog = new Dog("哈士奇");
dog.eat(); // 哈士奇喜歡吃骨頭
// dog.run(); // 這個(gè)時(shí)候就報(bào)錯(cuò)
}
我們會(huì)發(fā)現(xiàn)如果將子類(lèi)的實(shí)例賦值給了父類(lèi)的引用, 那么將只能使用父類(lèi)限定的方法, 子類(lèi)自己實(shí)現(xiàn)的自定義的方法將不能調(diào)用
3. Dart中的接口
3.1 dart 接口了解
官網(wǎng)的定義
一個(gè)類(lèi)通過(guò)使用關(guān)鍵字implements 來(lái)實(shí)現(xiàn)一個(gè)或者多個(gè)接口。
接口說(shuō)明:
- 通類(lèi)和抽象類(lèi)都可以作為接口,類(lèi)就是接口
- 一個(gè)普通類(lèi)要實(shí)現(xiàn)某個(gè)接口,覆寫(xiě)接口接口類(lèi)(普通或抽象類(lèi))的每個(gè)成員。
- 如果是復(fù)用已有類(lèi)的接口,使用繼承(extends)。
- 如果只是使用已有類(lèi)的外在行為,使用接口(implements)。
- 每個(gè)類(lèi)都隱式的定義了一個(gè)包含所有實(shí)例成員的接口
3.2 普通類(lèi)接口
3.2.1 定義普通類(lèi)
通過(guò)class關(guān)鍵字定義普通類(lèi)
class Person{
// 屬性
String name;
// 構(gòu)造函數(shù)
Person(this.name);
// 方法
void sayHello(){
print("大家好,我叫${name}");
}
}
void main(){
Person xm = new Person("小明");
xm.sayHello(); //大家好,我叫小明
}
3.2.2 extends關(guān)鍵字實(shí)現(xiàn)類(lèi)的繼承
定義子類(lèi)繼承這個(gè)父類(lèi)
// 父類(lèi)
class Person{
// 屬性
String name;
// 構(gòu)造函數(shù)
Person(this.name);
// 方法
void sayHello(){
print("大家好,我叫${name}");
}
}
// 子類(lèi)通過(guò)extends 繼承父類(lèi)的方法
class Student extends Person{
String name;
Student(this.name):super(name);
// 子類(lèi)自己的方法
void getInfo(){
print("他叫做${name}");
}
}
void main(){
Student xm = new Student("小明");
xm.sayHello(); //大家好,我叫小明
xm.getInfo(); // 他叫做小明
}
3.2.3 implements關(guān)鍵字實(shí)現(xiàn)接口
現(xiàn)在將父類(lèi)作為接口,讓子類(lèi)來(lái)實(shí)現(xiàn)這個(gè)接口
// 接口類(lèi)
class Person{
// 屬性
String name;
// 構(gòu)造函數(shù)
Person(this.name);
// 方法
void sayHello(){
print("大家好,我叫${name}");
}
}
// 實(shí)現(xiàn)接口類(lèi)
class Student implements Person{
// 覆寫(xiě)接口的屬性
@override
String name;
Student(this.name);
// 覆寫(xiě)接口的方法
@override
void sayHello(){
print("大家好,我叫${name}");
}
// 子類(lèi)自己的方法
void getInfo(){
print("他叫做${name}");
}
}
void main(){
Student xm = new Student("小剛");
xm.sayHello(); //大家好,我叫小剛
xm.getInfo(); // 他叫做小剛
}
這個(gè)時(shí)候我們就會(huì)發(fā)現(xiàn), 這是不是子類(lèi)繼承父類(lèi)的關(guān)系,而是父類(lèi)就是定義接口,實(shí)現(xiàn)接口的子類(lèi)要覆寫(xiě)接口中的所有屬性和方法.
3.3 抽象類(lèi)接口
建議:
將抽象類(lèi)作為接口使用(類(lèi)就是接口),讓子類(lèi)來(lái)實(shí)現(xiàn)(關(guān)鍵字implements來(lái)實(shí)現(xiàn))
因?yàn)槌橄箢?lèi)的所有的方法不用定義方法體, 而普通類(lèi)定義的方法需要實(shí)現(xiàn)方法體, 反正這些方法在作為接口的時(shí)候都是需要被實(shí)現(xiàn)接口的子類(lèi)覆寫(xiě)的,那么有沒(méi)有方法體已經(jīng)不重要了,所以推薦使用抽象類(lèi)作為接口
// 定義一個(gè)抽象類(lèi)接口
abstract class Db{
String uri;
// 抽象方法
add(String data);
save();
delete();
}
// Mysql 實(shí)現(xiàn)接口
class Mysql extends Db{
@override
String uri;
Mysql(this.uri);
// 子類(lèi)必須實(shí)現(xiàn)抽象類(lèi)的方法
@override
add(data){
print("這是Mysql的${data}");
}
@override
save(){
print("這是Mysql的save方法");
}
@override
delete(){
print("這是Mysql的delete方法");
}
}
void main(){
Mysql mysql = new Mysql("mysql");
mysql.add("123456"); // 這是Mysql的123456
mysql.save(); // 這是Mysql的save方法
mysql.delete(); // 這是Mysql的delete方法
}
4. Dart中一個(gè)類(lèi)實(shí)現(xiàn)多個(gè)接口
extends 關(guān)鍵字的繼承沒(méi)發(fā)做到多繼承,如果需要繼承多個(gè)類(lèi), extends是不能實(shí)現(xiàn)的,
那么我們就可以把需要繼承的類(lèi)作為接口,使用關(guān)鍵字implements來(lái)實(shí)現(xiàn)多個(gè)接口
還是要注意區(qū)分
-
extends是繼承 就算有些父類(lèi)的方法不覆寫(xiě),子類(lèi)的實(shí)例也能使用父類(lèi)的方法 -
implements是實(shí)現(xiàn)接口,不管實(shí)現(xiàn)多少父類(lèi)接口, 父類(lèi)里的所有方法都需要覆寫(xiě)的,
實(shí)現(xiàn)多接口的示例:
// 抽象類(lèi)A接口
abstract class A{
String name;
// 抽象方法
printA();
}
// 抽象類(lèi)B接口
abstract class B{
int age;
// 抽象方法
printB();
}
// Student 類(lèi)實(shí)現(xiàn) A和B 兩個(gè)接口
class Student implements A,B{
// 覆寫(xiě)接口的屬性
@override
String name;
int age;
Student(this.name,this.age);
// 實(shí)現(xiàn)A接口的方法
@override
void printA(){
print("實(shí)現(xiàn)A接口的方法");
}
// 實(shí)現(xiàn)B接口的方法
@override
void printB(){
print("實(shí)現(xiàn)B接口的方法");
}
// 子類(lèi)自己的方法
void sayHello(){
print("大家好, 我叫${name},今年${age}歲了");
}
}
// 入口函數(shù)
void main(){
// 實(shí)例化子類(lèi)
Student xm = new Student("小剛",8);
xm.printA(); // 實(shí)現(xiàn)A接口的方法
xm.printB(); // 實(shí)現(xiàn)B接口的方法
xm.sayHello(); //大家好, 我叫小剛,今年8歲了
}
5. 枚舉類(lèi)型
枚舉類(lèi)型也稱(chēng)為 enumerations或 enums , 是一種特殊的類(lèi),用于表示數(shù)量固定的常量值。
說(shuō)明:
- 使用
enum關(guān)鍵字定義一個(gè)枚舉類(lèi)型. - 枚舉是一種有窮序列集的數(shù)據(jù)類(lèi)型。
- 常用于代替常量,控制語(yǔ)句等
- 枚舉中的每個(gè)值都有
index,返回索引,索引從0開(kāi)始. - 枚舉中的每個(gè)值可以使用
values屬性列舉出來(lái)
枚舉的限制:
- 枚舉不能被子類(lèi)化,混合或?qū)崿F(xiàn)。
- 枚舉不能被顯式實(shí)例化。
// 定義枚舉
enum Color {
red,
green,
blue,
// 不能指定值,會(huì)報(bào)錯(cuò)的
// whie = "#fff"
}
// 入口函數(shù)
void main(){
// index 獲取索引
print(Color.red.index);
print(Color.green.index);
print(Color.blue.index);
// value
print(Color.red);
// 枚舉值
List list = Color.values;
print(list); //[Color.red, Color.green, Color.blue]
// 流程控制
var color = Color.red;
switch(color){
case Color.red:
print("紅色");
break;
case Color.green:
print("綠色");
break;
case Color.blue:
print("藍(lán)色");
break;
}
}
6. Mixin 混入
官方定義:
Mixin 是復(fù)用類(lèi)代碼的一種途徑, 復(fù)用的類(lèi)可以在不同層級(jí),之間可以不存在繼承關(guān)系。
簡(jiǎn)單說(shuō)就是在類(lèi)中混入其他的功能,實(shí)現(xiàn)類(lèi)似多繼承的功能
說(shuō)明:
- 使用
mixin關(guān)鍵字替換class定義混入類(lèi) - 作為
Mixin的類(lèi)只能繼承Object,不能繼承其他的類(lèi) -
Mixin類(lèi)似于多繼承,實(shí)在多類(lèi)繼承中重用一個(gè)類(lèi)代碼的方式。 - 作為
mixins的類(lèi)不能聲明構(gòu)造函數(shù),不能調(diào)用 super - 一個(gè)類(lèi)可以混入多個(gè)
Mixin類(lèi) - 使用
with方法實(shí)現(xiàn)類(lèi)似于多繼承 -
mixins絕不是繼承 也不是接口, 而是一種全新的特性
6.1 混入普通的類(lèi)
使用關(guān)鍵字with混入普通的類(lèi)
// 定義普通混入類(lèi)
class A{
String name = "AA";
printA(){
print("這是普通類(lèi)A");
}
}
class B{
String name = "BB";
printB(){
print("這是普通類(lèi)B");
}
}
// 混入兩個(gè)類(lèi)A,B
class Student with A,B{
}
// 入口函數(shù)
void main(){
// 實(shí)例化子類(lèi)
Student student = new Student();
print(student.name); // BB
student.printA(); // 這是普通類(lèi)A
student.printB(); // 這是普通類(lèi)B
}
在混入多個(gè)類(lèi)是,類(lèi)中有相同 的屬性或方法,后混入的會(huì)將先混入的覆蓋掉
6.2 使用mixin定義混入類(lèi)
// 使用mixin關(guān)鍵字定義混入類(lèi)
mixin A{
String name = "AA";
printA(){
print("這是普通類(lèi)A");
}
}
mixin B{
String name = "BB";
printB(){
print("這是普通類(lèi)B");
}
}
class Student with A,B{
}
// 入口函數(shù)
void main(){
// 實(shí)例化子類(lèi)
Student student = new Student();
print(student.name); // BB
student.printA(); // 這是普通類(lèi)A
student.printB(); // 這是普通類(lèi)B
}
6.3 注意混入的類(lèi)不能有構(gòu)造函數(shù)
無(wú)論是class定義的混入類(lèi),還是mixin定義的混入類(lèi), 有構(gòu)造函數(shù)就不錯(cuò)
但是如果class定義的類(lèi)不作為混入類(lèi)使用,就不會(huì)報(bào)錯(cuò)
// 混入類(lèi)不能有構(gòu)造函數(shù)會(huì)報(bào)錯(cuò)
// mixin 定義的混入類(lèi)
mixin A{
String name = "AA";
// A(this.name); // 報(bào)錯(cuò)
printA(){
print("這是普通類(lèi)A");
}
}
// class定義的混入類(lèi)
class B{
String name = "BB";
// B(this.name); // 報(bào)錯(cuò)
printB(){
print("這是普通類(lèi)B");
}
}
// 混入類(lèi)
class Student with A,B{
}
6.4 混入類(lèi)不能繼承其他類(lèi)
// 被繼承的類(lèi)
class Person{
int age ;
Person(this.age);
printInfo(){
print("被繼承的類(lèi)Person, 年紀(jì)${this.age}");
}
}
// B 是混入類(lèi),不能繼承其他類(lèi), 報(bào)錯(cuò)
class B extends Person{
printB(){
print("混入類(lèi)B");
}
}
// 混入
class Student with B{
}
6.5 混入不影響繼承
// 第一個(gè)類(lèi)
mixin A{
String name = "AA";
printA(){
print("這是普通類(lèi)A");
}
}
class B{
String name = "BB";
printB(){
print("這是普通類(lèi)B");
}
}
// 被繼承的類(lèi)
class Person{
int age ;
Person(this.age);
printInfo(){
print("被繼承的類(lèi)Person, 年紀(jì)${this.age}");
}
}
// 繼承一個(gè)類(lèi)混入兩個(gè)類(lèi)
class Student extends Person with A,B{
Student(int age):super(age);
}
void main(){
// 實(shí)例化類(lèi)
Student student = new Student(18);
// 繼承類(lèi)
student.printInfo(); // 被繼承的類(lèi)Person, 年紀(jì)18
// 混入類(lèi)的方法
print(student.name); // AA
student.printA(); // 這是普通類(lèi)A
student.printB(); // 這是普通類(lèi)B
}