Dart作為一種高級語言,支持面向對象的很多特性,並且支持基於mixin的繼承方式。 基於mixin的繼承方式是指:一個類可以繼承自多個父類,相當於其他語言里的多繼承。 所有的類都有同一個基類Object,這和特性類似於Java、Objective-C 等語言,Java所有的類也都是繼承自Objec ...
Dart作為一種高級語言,支持面向對象的很多特性,並且支持基於mixin的繼承方式。
基於mixin的繼承方式是指:一個類可以繼承自多個父類,相當於其他語言里的多繼承。
所有的類都有同一個基類Object,這和特性類似於Java、Objective-C 等語言,Java所有的類也都是繼承自Object,也就是說一切皆對象。
//實例化了一個User類的對象user var user = new User('Liming',25);
-
實例化成員變數
Class User{ String name;//name 成員變數 int age;//age 成員變數 }
類定義中所有的變數都會隱式的定義setter方法,針對非空的變數會額外增加getter方法。
實例化成員變數請參考如下代碼:
void main(){ var user = new User(); user.name = 'Liming';//相當於使用了name的setter方法 user.age = 25; }
-
構造函數
1.常規的構造函數
構造函數是用來構造當前類的函數,是一種特殊的函數,函數名稱必須要和類名相同才行.
如下代碼為User類添加了一個構造函數,函數里給User類的兩個成員變數初始化了值:
Class User{ String name; int age; User(String mName,int mAge){ this.name = mAge; this.age = mAge; } }
this關鍵字指向了當前類的實例
上面的代碼可以簡化為:
Class User{ String name; int age; User(this.name,this.age); }
第一種沒有簡化的構造方法初始化成員變數是在方法體內進行初始化的,
第二種簡化的構造方法初始化成員變數,是在實例化類的時候直接進行賦值初始化的。
2.命名的構造函數
使用命名構造函數是 從另一類或現有的數據中快速實現構造函數 ,代碼如下所示:
Class User{ String name; int age; //普通構造函數 User(this.name,this.age); //命名構造函數 User.fromJson(Map json){ name = json['name']; age = json['age']; } } //在實例化類的時候,如果沒有傳參,會預設調用無參數的構造方法 //普通構造函數 var user = new User('張三',25); //命名構造函數 var user = new User.fromJson(mMapJson);
3.子類的創建
註1:子類在繼承父類的時候,如果在父類中有顯示的提供一個無名、無參的構造函數,不會繼承父類無名有參構造函數和命名構造函數,即:子類只會繼承父類無名無參的構造函數。(程式會給類隱式的生成一個無名、無參的構造函數)
註2:子類在繼承父類的時候,如果在父類中沒有有顯示的提供一個無名、無參的構造函數,子類必須手動調用父類的一個構造函數,在這種情況下,調用的父類的構造函數要放在子類構造函數之後,在子類構造函數體之前,用“:”分隔。
註3:父類的構造函數會在子類的構造函數前調用。
註4:預設情況下,子類只能調用父類無名、無參數的構造函數。
註1和註3:父類中有一個無名、無參的構造函數,子類繼承父類,會預設繼承父類無名、無參的構造函數(即使有其他無名、有參的構造函數或者命名構造函數,子類都不會調用),並且,父類的無名、無參的構造函數會在子類的構造函數之前被調用。
Class Futher { //無名、無參的構造函數 Futher(){ print('我是父類無名、無參的構造函數'); } } Class Son extends Futher { //因為父類有顯式的聲明一個無名、無參的構造函數,所以不用手動調用父類的構造函數。 Son.fromJson(Map mMapJson){ print('我是子類的命名構造函數'); } } var son = new Son.fromJson(mMapJson); //列印結果 //我是父類無名、無參的構造函數 //我是子類的命名構造函
註2:下麵代碼里,子類的命名構造方法寫了兩種方式,第一種是正確的,第二種是錯誤的,有詳細的註釋, 如果有疑問請留言。
Class Futher { //無名、無參的構造函數 Futher.printSth(){ print('我是父類無名、無參的構造函數'); } } Class Son extends Futher { //因為父類沒有有顯式的聲明一個無名、無參的構造函數,所以需要手動的調用父類的構造函數。 Son.fromJson(Map mMapJson) : super Futher.printSth{ print('我是子類的命名構造函數'); } //這種寫法會報錯,因為父類中沒有顯示的提供一個無名、無參的構造函數。所以需要像上面那樣,手動調用父類的一個構造函數 Son.fromJson(Map mMapJson){ print('我是子類的命名構造函數'); } }
4.構造函數初始化列表
上面在講解常規的構造函數和命名構造函數的時候,示例代碼都有對類中的成員變數進行了初始化,
特點是在構造函數的方法體內進行初始化,初始化成員變數還有另一種方式,就是在構造函數運行前來初始化成員變數。
Class User { String name; int age; User(mName,mAge) :name = mName, age = mAge{ // Do Some Thing } }
特點是在構造函數的方法體前(大括弧前面)來初始化成員變數,變數間用“,”分隔。
-
讀取和寫入對象
get()和set()方法是專門用於讀取和寫入對象的屬性的方法,每一個類的實例,系統都會隱式的包含有get()和set()方法。
例如,定義一個矩形的類,有上、下、左、右:top、bottom、left、right四個成員變數,使用get及set關鍵字分別對right、bottom進行獲取和設置值。代碼如下所示:
Class Rectangle { num left; num top; num width; num height; Rectangle(this.left,this.top,this.width,this.height); num get right => left + width;//獲取righht的值(第一行) set right(num value) => left = value - width;//設置right的值,同時left也發生了變化(第二行) num get bottom => top + height;//獲取bottom的值(第三行) set bottom(num value) => top = value - height;//設置bottom值,同時top也發生了變化(第四行) } void main(){ var rect = new Rectangle(3,4,20,15);//實例化Rectangle,並給類中的4個變數進行初始化賦值 print('left:'+rect.left.toString());//獲取left的值,並列印 left = 3 print('right:'+rect.right.toString());//獲取right的值,並列印,這裡執行了Rectangle類中第一行代碼,right = left + width,right = 3+20 = 23 rect.right = 30;//重新給right進行賦值 right = 30,這裡執行了Rectabgke類中的第二行代碼,將right的值設置為30,並且,將left的值改為30 - 20,left = 30-20 = 10 print('right的值改為30'); print('left:'+rect.left.toString());//獲取left的值,並列印,因為上面給right重新賦值的時候,也改變了left的值,所以,此時left = 10 print('right:'+rect.right.toString());//rect.right = 30將right的值改為了30,所以,right = 30 print('top:'+rect.top.toString()); print('bottom:'+rect.bottom.toString()); rect.bottom = 50; print('bottom的值改為50'); print('top:'+rect.top.toString()); print('bottom:'+rect.bottom.toString()); } //列印結果 left:3 right:23 right的值改為30 left:10 right:30 top:4 bottom:19 bottom的值改為50 top:35 bottom:50
上面的示例註釋已經解釋的很清楚了,如果有任何疑問,請留言!!!
這裡我就解釋一下“=>”的作用,在Dart裡面,大家可以簡單的理解為接下來要繼續執行後面的操作。
-
重運算符載操作
在講解重載運算符前需要先說明Dart裡面的一個關鍵字operator,operator和運算符一起使用,表示一個運算符重載函數,在理解時可以將operator和運算符(如operator+或operator-)視為一個函數名。編寫一個例子方便理解。
Class Vector { final int x; final int y; const Vector(this.x,this.y); //重載加號 + (a+b) Vector operator + (Vector v){ return new Vector(x + v.x,y + v.y); } } void main() { //實例化兩個變數 final result1 = new Vector(10,20); final result2 = new Vector(30,40); final result = result1 + result2; print('result.x = '+result.x.toString()+'',+'result.y = '+result.y.toString()); //列印結果 result.x = 40,result.y = 60 }
首先創建了一個Vector類,聲明兩個成員變數x和y還有一個構造方法,在Vector類裡面重載一個加法運算符,重載操作返回Vector對象,接下來在main函數裡面,實例化了兩個Vector變數,兩次操作分別給
x和y進行了賦值,x = 10;y = 20;x = 30;y = 40。然後讓result1和result2這兩個變數相加,看到這裡大家可能會有疑問,兩個對象變數怎麼相加呢?這裡我們的運算符重載就發揮出作用了,實際上,在執行final result = result1 + result2;這行代碼的時候,其實是對象result1調用了"operator +"這個函數,並將result2這個對象當作一個參數傳遞給了這個函數,從而實現了對象result1中的x和對象result2中的x相加,對象result1中的y和對象result2中的y相加的操作,所以最終列印的結果result.x = 40,result.y = 60。
註:對於 Dart 提供的所有操作符,通常只支持對於基本數據類型和標準庫中提供的類的操作,而對於用戶自己定義的類,如果想要通過該操作符實現一些基本操作(比如比較大小,判斷是否相等),就需要用戶自己來定義關於這個操作符的具體實現了。
-
繼承類
繼承是面向對象編程技術的一塊基石,因為它允許創建分等級層次的類。繼承就是子類繼承父類的特征和行為,使得子類對象具有父類的實例域和方法;或子類從父類繼承方法,使得子類具有父類相同的行為。Dart裡面使用extends關鍵字來實現繼承,super關鍵字來指定父類。
Class Animal { void eat(){ print('動物會吃'); } void run(){ print('動物會跑'); } } Class Human extends Animal { void say(){ print('人會說'); } void study(){ print('人會學習'); } } void main(){ var animal = new Animal(); animal.eat(); animal.run(); value human = new Human(); human.eat(); human.run(); human.say(); human.study(); //列印結果 動物會吃 動物會跑 動物會吃 動物會跑 人會說 人會學習 }
-
抽象類
抽象類類似於Java語言中的介面。抽象類里不具體實現方法,只是寫好定義介面,具體實現留著調用的人去實現。抽象類可以使用abstract關鍵字定義類。
- 抽象類通過abstract關鍵字來定義。
- Dart中的抽象方法不能用abstract聲明,Dart中沒有方法體的方法我們成為抽象方法。
- 如果子類繼承了抽象類,就必須實現裡面的抽象方法。
- 如果把抽象類當作介面實現的話,就必須得實現抽象類裡面的所有屬性和方法。
- 抽象類不能實例化,只有繼承它的子類可以實例化。
abstract class Animal{ eat(); //抽象方法 run(); //抽象方法 printInfo(){ print('我是一個抽象類裡面的普通方法'); } } class Dog extends Animal{ @override eat() { print('小狗在吃骨頭'); } @override run() { // TODO: implement run print('小狗在跑'); } } class Cat extends Animal{ @override eat() { // TODO: implement eat print('小貓在吃老鼠'); } @override run() { // TODO: implement run print('小貓在跑'); } } void main(){ Dog d=new Dog(); d.eat(); d.printInfo(); Cat c=new Cat(); c.eat(); c.printInfo(); // Animal a=new Animal(); //抽象類沒法直接被實例化 }
Dart學習系列文章:https://www.cnblogs.com/jukaiit/category/1636484.html