Dart 語法學(xué)習(xí)目錄
第一節(jié): Dart 語法了解,認識變量,常量,數(shù)據(jù)類型
第二節(jié): Dart 操作符(運算符)
第三節(jié): Dart 中流程控制,條件判斷以及循環(huán)語句
第四節(jié): Dart 中常用集合 List/Map
第五節(jié): Dart 函數(shù)使用,聲明函數(shù)/匿名函數(shù)/可選參數(shù)/作用域/閉包
第六節(jié): Dart 面向?qū)ο?構(gòu)造函數(shù)/靜態(tài)屬性
第七節(jié): Dart中抽象類abstract/接口implements/混入Mixin
第八節(jié): Dart中泛型/泛型定義與使用
第九節(jié): Dart 中的庫/自定義庫/內(nèi)置庫/第三方庫
1. 面向?qū)ο蠼榻B
1.1 面向?qū)ο缶幊痰恼J識
面向?qū)ο缶幊?OOP)的三個特征是: 封裝,繼承,多態(tài)
- 封裝: 封裝是對象和類概念的主要特征, 封裝,把客觀事物封裝成抽象的類,并且把自己的部分屬性和方法提供給其他對象
- 繼承:面向?qū)ο缶幊陶Z言的主要功能就是繼承, 繼承是指一種能力
- 多態(tài): 允許將子類的指針賦值給父類類型的指針,同一個函數(shù)調(diào)用會有不同的執(zhí)行效果
1.2 Dart的面向?qū)ο笳J識
- Dart 是一個面向?qū)ο缶幊陶Z言溪北,同時支持基于
mixin
的繼承機制涤妒。 - 每個對象都是一個類的實例呻畸,所有的類都繼承于
Object
. - 基于 Mixin 的繼承 意味著每個類(Object 除外) 都只有一個超類,一個類的代碼可以在其他多個類繼承中重復(fù)使用以蕴。即一個類可以繼承自多個父類朝氓。
- 使用關(guān)鍵字
calss
聲明一個類 - 使用關(guān)鍵字
new
創(chuàng)建一個對象皆刺,new
可以省略。 - 對象的由函數(shù)和數(shù)據(jù)(即方法和實例變量)組成耐齐。
- 方法的調(diào)用要通過對象來完成: 調(diào)用的方法可以訪問其對象的其他函數(shù)和數(shù)據(jù)。
2. 創(chuàng)建使用類
2.1 定義類
通過class定義類,并在類中定義屬性和方法
示例:
class Person{
// 定義屬性
String name = "小明";
int age = 10;
// 定義方法
void getInfo(){
print("姓名:${this.name}--年紀:${this.age}")
}
}
2.2 使用類
void main(){
// 注意:student是Person的實例,所以變量的類型就是 Person類
Person student = new Person();
print(student); // Instance of 'Person' Person類的實例
// 調(diào)用實例的方法
student.getInfo(); // 姓名:小明--年紀:10
}
3. 默認構(gòu)造函數(shù)
我們會發(fā)現(xiàn),上一個例子中我們定義的方法,必須在我們手動調(diào)用的時候才會執(zhí)行, 其實我們也可以定義類似于JS ES6 類中的constructor 函數(shù)這樣的在實例化時默認調(diào)用的構(gòu)造函數(shù)
默認構(gòu)造函數(shù)的名稱必須與類名相同
如果未顯式定義默認構(gòu)造函數(shù)蒋情,會默認一個空的構(gòu)造函數(shù)埠况。
默認構(gòu)造函數(shù)沒有參數(shù),并且會調(diào)用超類的沒有參數(shù)的構(gòu)造函數(shù)棵癣。
3.1 未顯示定義默認構(gòu)造函數(shù)
class Person{
String name = "小明";
int age = 18;
void getInfo(){
print("name:$name---age: $age");
}
}
3.2 定義默認構(gòu)造函數(shù)
在通過這類實例化對象時會默認調(diào)用這個構(gòu)造函數(shù)
// 定義類
class Person{
// 定義屬性
String name = "小明";
int age = 10;
// 默認調(diào)用的構(gòu)造函數(shù)
Person(){
print("我是在類實例化時默認調(diào)用的函數(shù)");
}
// 定義方法
void getInfo(){
print("姓名:${this.name}--年紀:${this.age}");
}
}
// 入口函數(shù)
void main(){
// 實例化類
Person student = new Person();
/*
打印結(jié)果:
我是在類實例化時默認調(diào)用的函數(shù)
*/
}
上面的例子雖然在實例化時執(zhí)行了默認的構(gòu)造函數(shù), 但是我們會發(fā)現(xiàn)實例化對象的屬性是沒有變化的,
所以我們可以在默認構(gòu)造函數(shù)中根據(jù)實例化時傳遞的參數(shù)動態(tài)改變實例對象的屬性
3.3 默認構(gòu)造函數(shù)傳參
類在實例化是傳入的動態(tài)參數(shù)會在默認構(gòu)造函數(shù)執(zhí)行時形參所接收.
其中
this
關(guān)鍵字指當(dāng)前的實例辕翰。
示例:
// 定義類
class Person{
// 定義屬性
String name;
int age;
// 默認調(diào)用的構(gòu)造函數(shù)
Person(String name,int age){
this.name = name;
this.age = age;
}
// 定義方法
void getInfo(){
print("姓名:${this.name}--年紀:${this.age}");
}
}
void main(){
// 第一次實例化
Person student = new Person("小明",8);
student.getInfo(); // 姓名:小明--年紀:8
// 第二次實例化
Person student2 = new Person("小紅",10);
student2.getInfo(); //姓名:小紅--年紀:10
}
3.4 默認構(gòu)造函數(shù)傳參簡寫
其實默認的構(gòu)造函數(shù),如果只是修改實例屬性的話,我們還可以進行簡寫
class Person{
// 定義屬性
String name;
int age;
// 默認調(diào)用的構(gòu)造函數(shù)
// 直接將實例化傳遞過來的實參直接復(fù)制給實例屬性
// 簡寫方式
Person(this.name,this.age);
// 定義方法
void getInfo(){
print("姓名:${this.name}--年紀:${this.age}");
}
}
void main(){
Person student = new Person("小明",8);
student.getInfo(); // 姓名:小明--年紀:8
Person student2 = new Person("小紅",10);
student2.getInfo(); //姓名:小紅--年紀:10
}
3.5 實例化之前給屬性賦值
在默認構(gòu)造函數(shù)簡寫的情況下,接受實參的小括號后面添加:
就可以在實例化執(zhí)行默認構(gòu)造函數(shù)之前給實例屬性賦值;
可以在實例化之前給屬性賦值,但是沒什么意義
class Person{
// 定義屬性
String name;
int age;
// 默認調(diào)用的構(gòu)造函數(shù)
// 實例化之前給尚屬性賦值,沒什么意義
Person():name="默認",age=18{
print("姓名:${this.name}--年紀:${this.age}");
}
// 定義方法
void getInfo(){
print("姓名:${this.name}--年紀:${this.age}");
}
}
void main(){
Person student = new Person(); // 姓名:默認--年紀:18
}
注意:
4. 命名構(gòu)造函數(shù),
命名構(gòu)造函數(shù),是可以在實例化時通過類調(diào)用的方法
說明:
- 使用命名構(gòu)造函數(shù)可為一個類實現(xiàn)多個構(gòu)造函數(shù)
- 也可以使用命名構(gòu)造函數(shù)來更清晰的表明函數(shù)意圖
- 構(gòu)造函數(shù)不能夠被繼承, 這意味著父類的命名構(gòu)造函數(shù)不會被子類繼承
調(diào)用的方法:類名.命名構(gòu)造函數(shù)
class Person{
// 定義屬性
String name;
int age;
// 默認調(diào)用的構(gòu)造函數(shù)
Person(this.name,this.age);
// 命名構(gòu)造函數(shù)
Person.paly(this.name){
print("${this.name}在打游戲");
}
// 定義方法
void getInfo(){
print("姓名:${this.name}--年紀:${this.age}");
}
}
void main(){
// 通過類來調(diào)用的方法
Person.paly("小明"); // 小明在打游戲
}
可以把命名構(gòu)造函數(shù)當(dāng)成靜態(tài)方法來理解
5. 常量構(gòu)造函數(shù)
常量構(gòu)函數(shù)就是希望每次創(chuàng)建的對象都是同一個對象賦值給不同的變量.
說明:
- 如果該類生成的對象是固定不變的狈谊, 那么就可以把這些對象定義為編譯時常量喜命。
- 需要定義一個
const
構(gòu)造函數(shù), 并且聲明所有實例變量為final
河劝。 - 要使用常量構(gòu)造函數(shù)只需要用
const
替代new
即可渊抄,也可以省略const
。
示例:
class Person{
final name = "小明";
final age = 18;
const Person();
void getInfo(){
print("name:$name---age: $age");
}
}
void main(){
// 通過new 也可以創(chuàng)建一個對象,但不是常量構(gòu)造函數(shù)
Person student= new Person();
student.getInfo(); // name:小明---age: 18
Person student2= const Person();
student3.getInfo();
Person student3 = const Person();
student3.getInfo(); // name:小明---age: 18
// 可以通過identical方法來比較創(chuàng)建的對象是不是同一個對象
print(identical(student, student2)); // false
print(identical(student2, student3)); // true
}
通過結(jié)果我們可以發(fā)現(xiàn), 通過new
關(guān)鍵字創(chuàng)建出來的對象和通過const
創(chuàng)建出來的對象不是同一個
但是兩個const
創(chuàng)建出來的對象是同一個對象.
6. 可以 將類抽離為單獨的文件
可以將類抽離為單獨的文件, 然后通過import 引入, 這樣模塊化的開發(fā)方式利于多協(xié)同開發(fā)
// 抽離的類
// lib/Person.dart
class Person{
// 定義屬性
String name;
int age;
// 默認調(diào)用的構(gòu)造函數(shù)
Person(this.name,this.age);
// 命名構(gòu)造函數(shù)
Person.paly(this.name){
print("${this.name}在打游戲");
}
// 定義方法
void getInfo(){
print("姓名:${this.name}--年紀:${this.age}");
}
}
引入類
// main.dart
// 引入模塊的文件
import "lib/Person.dart";
void main(){
// 然后就可以使用抽離的類了
Person.paly("小明"); // 小明在打游戲
Person student = new Person("小明", 8);
student.getInfo(); //姓名:小明--年紀:8
}
7. 私有屬性私有方法
dart中定義私有屬性或方法通過_
來定義
但是要注意, 類必須抽離成單獨的文件私有屬性和方法才可以使用 ,否則沒有效果
7.1 定義類和使用類在同一文件里
定義類和使用類在同一文件里, 私有屬性沒用
class Person{
// 定義屬性
// _name 為私有屬性
String _name;
int age;
// 默認調(diào)用的構(gòu)造函數(shù)
Person(this._name,this.age);
// 定義方法
// _getInfo為私有方法
void _getInfo(){
print("姓名:${this._name}--年紀:${this.age}");
}
}
void main(){
Person student = new Person("小明", 8);
student._getInfo(); //姓名:小明--年紀:8
}
7.2 類的創(chuàng)建和調(diào)用在不同的文件
// 定義類
// lib/Person.dart
class Person{
// 定義屬性
// 定義私有屬性_name
String _name;
int age;
// 默認調(diào)用的構(gòu)造函數(shù)
Person(this._name,this.age);
// 私有方法
void _getInfo(){
print("姓名:${this._name}--年紀:${this.age}");
}
// 實例方法
// 通過實例方法getInfo調(diào)用私有方法_getInfo
// 也就是說, 私有屬性和私有方法,
void getInfo(){
this._getInfo();
}
}
調(diào)用類, 私有屬性方法只能通過實例方法去調(diào)用獲取
void main(){
Person student = new Person("小明", 8);
// student._getInfo(); // 實例調(diào)用私有方法報錯
// print(student._name); // 實例調(diào)用私有屬性報錯
// print(Person._name); // 類調(diào)用私有屬性也報錯
print(student.age); // 8
// 私有屬性和私有方法只能在實例的方法中調(diào)用
student.getInfo(); // 姓名:小明--年紀:8
}
8. 類中g(shù)etter 和setter修飾符
getter和setter定義的函數(shù)名不能更屬性重名, 因為getter,setter定義的函數(shù)是計算屬性, 也就是是函數(shù)名會是屬性, 函數(shù)的返回值會自動計算為屬性的值;
說明:
-
Getter
和Setter
是用于對象屬性讀和寫的特殊函數(shù)丧裁。 - 每個實例變量都有一個隱式
Getter
护桦,如果變量不是final,通常情況下還會有一個Setter
- 使用
get
和set
關(guān)鍵字實現(xiàn) Getter 和 Setter ,能夠為實例創(chuàng)建新屬性煎娇。 - 計算屬性的值是通過計算而來二庵,本身不存儲值。
- 計算屬性賦值缓呛,其實是通過計算轉(zhuǎn)換到其他實例變量催享。
實例:
class Person{
// 定義屬性
String _name;
int age;
// 默認調(diào)用的構(gòu)造函數(shù)
Person(this._name,this.age);
// 獲取計算屬性
get getInfo{
return "${this._name}:${this.age}";
}
// 設(shè)置計算屬性
set setName(value){
this._name = value;
}
}
void main(){
Person student = new Person("小明", 8);
// 操作計算屬性
print(student.getInfo); // 小明:8
student.setName = "小紅";
print(student.getInfo); // 小紅:8
}
9. 靜態(tài)屬性和靜態(tài)方法
dart中的靜態(tài)成員
- 使用static 關(guān)鍵字來實現(xiàn)類級別的變量和函數(shù)
- 靜態(tài)方法不能訪問非靜態(tài)成員, 非靜態(tài)方法可以訪問靜態(tài)成員
- 靜態(tài)方法不能在類的實例上使用, 因此無法訪問 this(this值得是類的實例)
- 靜態(tài)變量對于類級別的狀態(tài)是非常有用的哟绊。
- 靜態(tài)變量在被使用的時候才被初始化因妙。
實例
class Person{
// 靜態(tài)屬性
static String name ="小明";
// 非靜態(tài)屬性
int age;
// 默認調(diào)用的構(gòu)造函數(shù)
Person(name,this.age);
// 靜態(tài)方法
static void getInfo(){
print(name);
// 靜態(tài)方法不能調(diào)用非靜態(tài)屬性或方法
// 靜態(tài)方法中不能使用this
// print("${name}:${this.age}"); // 報錯
// this.setName(); // 報錯
}
// 非靜態(tài)方法
void setName(){
// 非靜態(tài)方法可以調(diào)用靜態(tài)屬性或方法,調(diào)用的使用不需要通過this調(diào)用
print("${name}:${this.age}");
getInfo();
}
}
void main(){
Person student = new Person("小明", 8);
// 使用類調(diào)用靜態(tài)方法,
Person.getInfo(); // 小明
// 實例調(diào)用非靜態(tài)方法, 非靜態(tài)方法可以調(diào)用靜態(tài)方法
student.setName();
/*
* 小明:8
* 小明
* */
}
10. 對象的操作符
- ? 條件運算符(了解)
- as 類型轉(zhuǎn)換
- is 類型判斷
- .. 級聯(lián)操作(鏈式調(diào)用)
10.1 條件運算符,
判斷是以對象是存在,存在就調(diào)用方法, 不存在就不調(diào)用方法
class Person{
// 屬性
String name ="小明";
int age = 18;
void getInfo(){
print("${name}:${this.age}");
}
}
void main(){
// 這么調(diào)用沒有任何問題
// Person student = new Person();
// student.getInfo();
// 如果沒有實例化呢
// Person student ;
// 沒有實例化就調(diào)用方法會報錯
// student.getInfo();
// 所以我們要先判斷在調(diào)用
Person student ;
// 如果student 有這個方法就調(diào)用沒有,也不會報錯
student?.getInfo();
}
10.2 類型轉(zhuǎn)換
類型轉(zhuǎn)換使用關(guān)鍵字 as
class Person{
// 屬性
String name ="小明";
int age = 18;
void getInfo(){
print("${name}:${this.age}");
}
}
void main(){
var student;
student = '';
student = new Person() ;
// 現(xiàn)在這么調(diào)用沒有什么問題, 以前會報錯
// 就是student 不能識別自己是字符串類型還是Person類型
// student.getInfo();
// 所以以前需要類型轉(zhuǎn)換
(student as Person).getInfo()
}
10.3 類型判斷
類型判斷使用is
class Person{
// 屬性
String name ="小明";
int age = 18;
void getInfo(){
print("${name}:${this.age}");
}
}
void main(){
var student;
student = '';
student = new Person() ;
// 判斷是不是Person類型
print(student is Person); // true
}
其他類型的判斷
void main(){
var str = "";
print(str is String); // true
int num = 123;
print(num is int); // true
bool boolean = true;
print(boolean is bool); // true
List list = ['a','b'];
print(list is List); // true
Map map = {"name":"aa"};
print(map is Map); // true
}
10.4 聯(lián)級調(diào)用
就是可以通過..聯(lián)級一次給實例添加多個屬性
class Person{
// 屬性
String name ="小明";
int age = 18;
String sex = "男";
void getInfo(){
print("${this.name}:${this.age}:${this.sex}");
}
}
void main(){
Person student = new Person() ;
student.getInfo(); // 小明:18:男
// 修改屬性值
// student.name = "小紅";
// student.age = 14;
// student.sex = "女";
// student.getInfo(); // 小紅:14:女
// 修改多個屬性值可以使用聯(lián)級調(diào)用
// 結(jié)果完全一樣
student..name = "小紅"
..age = 14
..sex = "女";
student.getInfo(); // 小紅:14:女
}
11. Dart中類的繼承
子類使用extents關(guān)鍵詞來繼承父類
子類會繼承父類里面可見的屬性和方法, 但不會繼承構(gòu)造函數(shù)
子類能覆寫父類的方法
11.1 繼承父類
子類使用extents關(guān)鍵字繼承父類
// 父類
class Person{
// 屬性
String name ="小明";
int age = 18;
// 方法
void getInfo(){
print("${this.name}:${this.age}");
}
}
// 子類
// 子類通過extends 繼承父類
class Student extends Person{
}
void main(){
// 通過子類實例化對象
Student student = new Student();
// 繼承父類的屬性
print(student.name); // 小明
// 繼承了父類的方法
student.getInfo(); // 小明:18
}
11.2 使用關(guān)鍵字super來給父類的構(gòu)造函數(shù)傳參
實例化子類給父類傳值
class Person{
// 屬性
String name ;
int age ;
// 構(gòu)造函數(shù)
Person(this.name, this.age);
// 方法
void getInfo(){
print("${this.name}:${this.age}");
}
}
// 子類
// 如果父類的屬性是需要通過構(gòu)造函數(shù)傳參的
// 那么子類在繼承的時候就需要通過super來給父類傳參
class Student extends Person{
// 子類先后去實例化時傳遞過來的實參
// 子類獲取實參后再將數(shù)據(jù)通過super 傳遞給父類的構(gòu)造函數(shù)
Student(String name,int age):super(name,age);
}
void main(){
// 通過子類實例化對象
Student student = new Student("小明", 18);
// 繼承父類的屬性
print(student.name); // 小明
// 繼承了父類的方法
student.getInfo(); // 小明:18
}
同時我們也可以擴展自己的屬性和方法
// 父類
class Person{
// 屬性
String name ;
int age ;
// 構(gòu)造函數(shù)
Person(this.name, this.age);
// 方法
void getInfo(){
print("${this.name}:${this.age}");
}
}
// 子類
class Student extends Person{
// 擴展子類自己的屬性
String sex;
Student(String name,int age,String sex):super(name,age){
this.sex = sex;
}
// 擴展子類自己的方法
void getStudentInfo(){
print("${this.name}:${this.age}:${this.sex}");
}
}
void main(){
// 通過子類實例化對象
Student student = new Student("小明", 18,"男");
// 繼承父類的屬性
print(student.name); // 小明
// 繼承了父類的方法
student.getInfo(); // 小明:18
// 調(diào)用子類自己的方法
student.getStudentInfo(); // 小明:18:男
}
還可以給父類里的命名構(gòu)造函數(shù)傳參
// 父類
class Person{
// 屬性
String name ;
int age ;
// 構(gòu)造函數(shù)
Person(this.name, this.age);
// 父類的命名構(gòu)造函數(shù)
Person.sayHello(String name){
print("${name} 說你好");
}
// 方法
void getInfo(){
print("${this.name}:${this.age}");
}
}
// 子類
class Student extends Person{
// 擴展子類自己的屬性
String sex;
Student(String name,int age,String sex):super(name,age){
this.sex = sex;
}
// 給父類的命名構(gòu)造函數(shù)傳參
Student.sayHello(String name):super.sayHello(name);
// 擴展子類自己的方法
void getStudentInfo(){
print("${this.name}:${this.age}:${this.sex}");
}
}
void main(){
// 通過子類實例化對象
Student student = new Student("小明", 18,"男");
// 調(diào)用子類的命名構(gòu)造函數(shù)
Student.sayHello("哈哈"); // 哈哈 說你好
}
11.3 覆寫父類方法
所謂的復(fù)寫,就是子類定義一個更父類同名的方法, 當(dāng)子類調(diào)用這個同名方法的時候,優(yōu)先使用子類自己的方法, 看起來就像把父類的同名方法覆蓋了
覆寫父類的方法時建議使用關(guān)鍵字: @override(可寫可不寫)
// 父類
class Person{
// 屬性
String name = "小明";
int age = 18 ;
// 方法
void getInfo(){
print("${this.name}:${this.age}");
}
}
// 子類
class Student extends Person{
// 覆寫父類的方法
@override // 覆寫的時候加上這個,不寫也可以,一般寫上會比較好,知道這個方法是覆寫方法
void getInfo(){
print("覆寫了父類的方法");
}
}
void main(){
// 通過子類實例化對象
Student student = new Student();
student.getInfo(); // 覆寫了父類的方法
}
11.4 子類擴展父類的方法
子類方法里調(diào)用父類的方法
對父類的方法進行擴展
// 父類
class Person{
// 屬性
String name = "小明";
int age = 18 ;
// 方法
void getInfo(){
print("${this.name}:${this.age}");
}
}
// 子類
class Student extends Person{
// 調(diào)用父類方法, 擴展父類方法的功能
void sayHello(){
// 在子類的方法里調(diào)用父類的方法
super.getInfo();
// 擴展父類方法的功能
print("${this.name}說你們好");
}
}
void main(){
// 通過子類實例化對象
Student student = new Student();
student.sayHello(); // 擴展父類功能的子類方法
/*
小明:18
小明說你們好
*/
}