Dart做爲高級語言,支持面向對象的不少特性,而且支持基於mixin的繼承方式,基於mixin的繼承方式是指:一個類能夠繼承自多個父類,至關於其餘語言裏的多繼承。全部的類都有同一個基類Object,這和特性相似於Java語言,Java全部的類也都是繼承自Object,也就是說一切皆對象。html
//實例化了一個User類的對象user var user = new User('張三',20);
Class User{ String name;//name 成員變量 int age;//age 成員變量 }
類定義中全部的變量都會隱式的定義setter方法,針對非空的變量會額外增長getter方法。實例化成員變量請參考以下代碼:編程
main(){ var user = new User(); user.name = '張三';//至關於使用了name的setter方法 user.age = 25; }
構造函數是用來構造當前類的函數,是一種特殊的函數,函數名稱必需要和類名相同才行,以下代碼爲User類添加了一個構造函數,函數裏給User類的兩個成員變量初始化了值:json
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); }
第一種沒有簡化的構造方法初始化成員變量是在方法體內進行初始化的,第二種簡化的構造方法初始化成員變量,是在實例化類的時候直接進行賦值初始化的。異步
使用命名構造函數從另外一類或現有的數據中快速實現構造函數,代碼以下所示:ide
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);
我對命名構造函數的理解就是起了個名字,在Java裏面,相同參數個數的構造方法只能有一個,在Dart裏面也不例外,那麼若是咱們想有多個相同參數個數的構造方法要怎麼作呢,這時候命名構造方法就顯現出他價值了,咱們能夠給相同參數個數的構造方法起不一樣的名字,這種就不會有錯誤了。函數
注1:子類在繼承父類的時候,若是在父類中有顯示的提供一個無名、無參的構造函數,不會繼承父類無名有參構造函數和命名構造函數,即:子類只會繼承父類無名無參的構造函數。(程序會給類隱式的生成一個無名、無參的構造函數)post
注2:子類在繼承父類的時候,若是在父類中沒有有顯示的提供一個無名、無參的構造函數,子類必須手動調用父類的一個構造函數,在這種狀況下,調用的父類的構造函數要放在子類構造函數以後,在子類構造函數體以前,用「:」分隔。學習
注3:父類的構造函數會在子類的構造函數前調用。this
注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('我是子類的命名構造函數'); } }
上面在講解常規的構造函數和命名構造函數的時候,示例代碼都有對類中的成員變量進行了初始化,特色是在構造函數的方法體內進行初始化,初始化成員變量還有另外一種方式,就是在構造函數運行前來初始化成員變量。
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也發生了變化(第四行) } 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); } } 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('人會學習'); } } main(){ var animal = new Animal(); animal.eat(); animal.run(); value human = new Human(); human.eat(); human.run(); human.say(); human.study(); //打印結果 動物會吃 動物會跑 動物會吃 動物會跑 人會說 人會學習 }
抽象類相似於Java語言中的接口。抽象類裏不具體實現方法,只是寫好定義接口,具體實現留着調用的人去實現。抽象類可使用abstract關鍵字定義類。
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('小貓在跑'); } } main(){ Dog d=new Dog(); d.eat(); d.printInfo(); Cat c=new Cat(); c.eat(); c.printInfo(); // Animal a=new Animal(); //抽象類無法直接被實例化 }
枚舉類型是一種特殊的類,一般用來表示相同類型的一組常量值,用enum來定義,每一個枚舉類型都有一個index和getter,index用來標記元素的元素位置。第一個枚舉元素的索引是0,枚舉不能被繼承,不能建立實例。
//定義一個枚舉類 enum Color { red, green, blue } //打印枚舉類中green的索引 print(Color.green.index); // 1 //獲取枚舉類中全部的值,使用value常數 List<Color> colorList = Color.values;
由於枚舉類中的每一個元素都是相同類型,因此可使用switch語句來針對不一樣的值作不一樣的處理,示例代碼以下:
//定義一個枚舉類 enum Color { red, green, blue } main(){ Color mColor = Color.blue; switch (mColor){ case Color.red: print('紅色'); break; case Color.green: print('綠色'); break; case Color.blue: print('藍色'); break; default: break; } //打印結果 藍色 }
Mixins(混入功能)至關於多繼承,也就是說能夠繼承多個類,使用with關鍵字來實現Mixins的功能,示例代碼以下:
Class First { void printSth(){ print('im first printSth'); }; } Class Second { void printSth(){ print('im Second printSth'); }; void secondPrint(){ print('test'); } } Class A = Second with First; main (){ A a = new A(); a.printSth(); a.secondPrint(); //打印結果 im first printSth test }
這段示例代碼,是將類First混入到了Second類中並給了類A,這塊我在學習的時候有個疑問,一樣的printSth方法,將First混入到Second後,打印的是First中的im first printSth,這是由於First中的printSth方法將Second中的printSth方法覆蓋了嘛?
泛型一般是爲了類型安全而設計的,適當的指定泛型類型會生成更好的代碼,可使用泛型來減小代碼重複,Dart中使用<T>的方式來定義泛型。例如,若是想要List只包含字符串,能夠將其聲明爲list<String>。以下所示:
var names = new List<String>(); names.addAll(['張三','李四','王五']);
泛型用於List和Map類型參數化:
List:<type> Map:<keyType,valueType> var names = new List<String>['張三','李四','王五']; var weeks = new Map<String,String>{ 'Monday’' : '星期一', 'Tuesday' : '星期二', 'Wednesday' : '星期三', 'Thursday' : '星期四', 'Friday' : '星期五', 'Saturday' : '星期六', };
經過import語句在一個庫中引用另外一個庫的文件,須要注意一下事項:
import的例子以下:
import 'dart:io'; import 'package:mylib/mylib.dart';
當引用的庫擁有相互衝突的名字,能夠爲其中一個或幾個指定不同的前綴,這與命名空間的概念比較接近,示例代碼以下:
import 'package:lib1/lib1.dart'; import 'package:lib2/lib2.dart' as lib2; Element emelent1 = new Element();//默認使用lib1裏面的Element lib2.Element emelent2 = new lib2.Element();//使用lib2裏面的Element
lib1/lib1.dart及lib2/lib2.dart裏面都有Element類,若是直接引用就不知道具體引用哪一個Element類,因此代碼中把lib2/lib2.dart指定成lib2,這樣使用lib2.Element就不會發生衝突。 3.引用庫的一部分若是隻須要使用庫的一部份內容,能夠有選擇的進行引用,有以下關鍵字:
示例代碼以下:
//導入foo import 'package:lib1/lib1.dart' show foo; //除了foo導入其餘全部內容 import 'package:lib1/lib1.dart' hide foo;
使用元數據給代碼添加更多的信息,元數據是以@開始的修飾符,在@後面接着編譯時的常量或調用一個常量的構造函數。目前Dart語言提供了三個@修飾符:
1.@deprecated 被棄用的
2.@override 重寫
3.proxy 代理
使用@override修飾符能夠重寫父類的方法。人類重寫eat方法,代碼以下所示:
//動物類 Class Animal { void eat(){ print('動物會吃'); } void run(){ print('動物會跑'); } } //人類 Class Human extends Animal { void say(){ print('人會說'); } @override void eat(){ print('人類也會吃的哦'); } } main(){ var animal = new Animal(); animal.eat(); animal.run(); value human = new Human(); human.say(); human.eat(); //打印結果 動物會吃 動物會跑 人會說 人類也會吃的哦 }
元數據能夠修飾library(庫)、class(類)、typedef(類型定義)、type parameter(類型參數)、constructor(構造函數)、factory(工廠函數)、function(函數)、field(做用域)、parameter(參數)、variable declaration(變量聲明)。