Dart 是一門面向對象的語言, 全部的類都是繼承自 Object
, 除了支持傳統的 繼承、封裝、多態
, 還有基於組合(Mixin-based)的繼承特性, 這個特性也是本文將會重點介紹的地方json
既然是面向對象的語言, 先讓咱們來看下如何定義一個類:緩存
class ClassName{
}
複製代碼
經過 class
關鍵字定義類, 語法和其餘主流的語言沒有什麼差異bash
有過使用面嚮對象語言經驗的開發者知道, 通常類由成員變量, 成員方法, 構造方法, 靜態變量, 靜態方法
組成ide
下面咱們來看下如何聲明成員變量:函數
class Point {
// 聲明成員變量 x
num x;
// 聲明成員變量 y
num y;
}
複製代碼
成員變量默認會生成一個隱式的 getter
方法, 而且 非final
的成員變量也會隱式的生成 setter
方法post
除此之外, 開發者還可使用 get
和 set
關鍵字實現 getter
和 setter
方法來建立新的屬性, 如:學習
class Rectangle {
num left, top, width, height;
// 構造函數
Rectangle(this.left, this.top, this.width, this.height);
// 定義兩個屬性: right and 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;
}
複製代碼
聲明靜態變量, 在前面聲明成員變量的基礎上加上 static
關鍵字:測試
class Person{
// 靜態變量
static var count = 0;
// 靜態常量
//static const var count = 0;
}
複製代碼
若是定義函數已經在 (三)Flutter學習之Dart函數 介紹過了ui
類的成員方法就是把之前介紹的方法定義到類裏面而已this
class Person {
void sayHello() {
print("hello...");
}
}
void main() {
var p = Person();
p.sayHello();
}
複製代碼
類的靜態方法, 就是在成員方法基礎上加上 static
關鍵字, 訪問的時候只須要類名便可而不須要對象, 這個和 Java 是同樣的
class Person {
static void printDesc() {
print("this is person description...");
}
}
void main() {
Person.printDesc();
}
複製代碼
在類中建立一個和類名同樣的函數這就是構造函數, 如:
class Point {
// 成員變量
num x, y;
// 構造方法
Point(num x, num y) {
this.x = x;
this.y = y;
}
}
複製代碼
Dart 爲咱們提供了語法糖來簡化上面的代碼:
class Point {
num x, y;
// 聲明構造方法, 接受兩個參數, 而且將參數分別賦值給對應的變量上
Point(this.x, this.y);
}
複製代碼
Dart 還爲咱們提供了 Named constructor
, 讓代碼可讀性更高, 讓開發者經過名字就知道該構造方法是幹什麼的
class Person {
String firstName;
// 聲明 Named constructor
Person.fromJson(Map data) {
print('in Person');
}
}
void main() {
var p = Person.fromJson({});
}
複製代碼
若是想將構造方法聲明爲 private 的, 加上下劃線便可:
// 私有構造函數, 只能在當前類可用
Person._fromJson(Map data) {
print('in Person');
}
複製代碼
構造方法還能夠調用另外一個構造方法:
class Point {
num x, y;
Point(this.x, this.y);
// 經過 this 關鍵字調用其餘構造函數
Point.alongXAxis(num x) : this(x, 0);
}
複製代碼
除了在構造方法中調用其餘的構造方法, 還能夠調用父類的構造方法:
class Employee extends Person {
// 經過 super 關鍵字調用父類的構造方法
Employee.fromJson(Map data) : super.fromJson(data) {
print('in Employee');
}
}
複製代碼
初始化器列表(Initializer list)
Dart 還支持 初始化器列表(Initializer list)
, 它在構造方法體執行以前執行, 在構造方法後用 冒號(:)
分隔初始化器列表
, 例如:
Point.fromJson(Map<String, num> json)
: x = json['x'],
y = json['y'] {
print('In Point.fromJson(): ($x, $y)');
}
複製代碼
因爲初始化器列表
初始化成員變量操做是在構造方法體執行前執行, 因此初始化器列表
中不能使用 this
關鍵字
在開發期間還能夠在初始化器列表
中使用斷言:
Point.withAssert(this.x, this.y) : assert(x >= 0) {
print('In Point.withAssert(): ($x, $y)');
}
複製代碼
若是某個類建立對象後再也不發生更改, 能夠將對象聲明爲運行時常量, 將對象聲明爲常量, 須要將類的構造方法聲明爲常量構造方法
而且全部的成員變量都必須是 final
的
class ImmutablePoint {
final num x, y;
const ImmutablePoint(this.x, this.y);
}
複製代碼
若是建立兩個常量對象, 實際上他們是一個對象實例:
var a = const ImmutablePoint(1, 1);
var b = const ImmutablePoint(1, 1);
// They are the same instance!
assert(identical(a, b));
複製代碼
工廠構造器(Factory Contructor)
工廠構造器就構造方法前面使用 factory
關鍵字修飾:
factory Person(String name){
}
複製代碼
其實這不是嚴格意義上的構造函數, 在其方法體內不能訪問 this
, 只是爲了調用該方法的時候就像調用普通的構造方法同樣
而不用關心究竟是返回了一個新的對象仍是緩存的對象. 例以下面一個單例模式的代碼:
class Singleton {
static final Singleton _singleton = new Singleton._internal();
factory Singleton() {
return _singleton;
}
// 將默認的構造函數聲明爲private
Singleton._internal();
}
main() {
// 就像調用普通的構造方法同樣
var s1 = Singleton();
var s2 = Singleton();
print(identical(s1, s2)); // true
print(s1 == s2); // true
}
複製代碼
抽象類使用 abstract
修飾符來修飾, 抽象類不能被實例化, 若是抽象類裏的方法沒有方法體, 那麼表示該方法是抽象方法:
abstract class AbstractContainer {
// 抽象方法
void updateChildren();
List getChildren(){
return container;
}
}
複製代碼
定義接口並無特殊的關鍵字, 使用 class 關鍵字來定義接口, 只不過裏面的方法都是沒有方法體的抽象方法
// A person. The implicit interface contains greet().
class Person {
// In the interface, but visible only in this library.
final _name;
// Not in the interface, since this is a constructor.
Person(this._name);
// In the interface.
String greet(String who) => 'Hello, $who. I am $_name.';
}
複製代碼
實現接口的時候須要使用 implements
關鍵字:
class Point implements Comparable, Location {...}
複製代碼
不論是繼承抽象類仍是普通類, 使用 extends
關鍵字
若是重載父類的方法時, 須要調用父類的方法, 使用 super 關鍵字
class Television {
void turnOn() {
_illuminateDisplay();
_activateIrSensor();
}
}
class SmartTelevision extends Television {
@override
void turnOn() {
super.turnOn();
_bootNetworkInterface();
_initializeMemory();
_upgradeApps();
}
}
複製代碼
經過上面介紹咱們知道繼承一個類使用 extends
關鍵字, 實現一個接口使用 implements
關鍵字
若是使用 implements
關鍵字實現一個非接口的類, 如:
class A {}
class B implements A{}
複製代碼
在 Dart
中這是容許的, 在 Java
中 implements
關鍵後面只能放接口
若是 implements
一個非接口類, 須要實現該類的裏面的全部方法:
class A {
void sayHello(){
print("My name is A");
}
}
class B implements A{
@override
void sayHello() {
print("My name is B");
}
}
複製代碼
Dart 中的 mixin 特性主要是用來多個層級類的代碼重用
Dart 和 Java 同樣都是單繼承的,也就是說若是要複用多個類的代碼,經過繼承的方式是行不通的
在 Dart 中經過 with 關鍵字來實現 mixin 特性:
class Fly{
void fly(){
print("flying");
}
}
class Animal{
}
class Bird extends Animal with Fly{
}
main(){
Bird().fly();
}
複製代碼
從中能夠看出,咱們能夠經過非繼承的方式來使用 Fly
類的功能
Bird
除了具備 fly
的功能,還有 run
的功能, 咱們經過 mixin
多個類來實現:
class Run {
void run() {
print("running");
}
}
class Bird extends Animal with Fly, Run {}
main() {
var bird = Bird();
bird.fly();
bird.run();
}
複製代碼
可以被 mixin 的類須要知足必定的條件:
上面的 Bird
繼承了 Animal
, 而後 mixin Fly
這個類, 若是 Animal
中也有 fly
方法它會選擇執行哪一個 fly
方法呢
class Animal {
void fly() {
print("Animal flying");
}
}
複製代碼
通過測試發現會使用 Fly
類裏的 fly
方法, 也就是說 mixin
Class 比 extends
Class 優先級要高
若是咱們 mixin 多個類, 在這多個類中包含了相同的方法, Dart會選擇執行哪一個呢?
class FlyEnhance{
void fly() {
print("fly enhance");
}
}
class Bird extends Animal with Run, Fly, FlyEnhance {}
main() {
var bird = Bird();
bird.fly();
bird.run();
}
//輸出結果:
fly enhance
running
複製代碼
類 Fly, FlayEnhance
中都有 fly
方法, 經測試發現, 使用哪一個類的 fly
方法取決於 with
後面順序, 後面的 FlyEnhance
會覆蓋前面的 Fly
中的 fly 方法
mixin 多個類的原理分析
上面的代碼:
class Bird extends Animal with Run, Fly, FlyEnhance {}
複製代碼
底層會建立多個類來實現這個功能, 至關於下面的代碼:
class $AnimalRun Animal with Run
class $AnimalRunFly extends $AnimalRun with Fly
class $AnimalRunFlyFlyEnhance extends $AnimalRunFly with FlyEnhance
class Bird extends $AnimalRunFlyFlyEnhance
複製代碼
因此上面的代碼會額外建立三個類, 因爲 mixin
優先級高於 extends
, 因此:
// 使用 Fly 裏的 fly 方法
class $AnimalRunFly extends $AnimalRun with Fly
// 使用 FlyEnhance 裏的 fly 方法
class $AnimalRunFlyFlyEnhance extends $AnimalRunFly with FlyEnhance
複製代碼
這就是 Dart 爲何最終會選擇使用 FlyEnhance
而不是 Fly
裏的 fly()
方法
若是一個類使用 mixin 特性, 那麼這個類的實例也是 mixin 類的子類型:
print(bird is Animal);
print(bird is Run);
print(bird is Fly);
print(bird is FlyEnhance);
//true
複製代碼
若是一個類只用於被 mixin
, 能夠在聲明類的時候使用 mixin
關鍵字代替 class
關鍵字
這個類則不能被繼承(extends), 但能夠被實現(implements)
還能夠經過 on
關鍵字來指定 mixin
類的須要的父類
class SuperA{
}
mixin A on SuperA{
}
複製代碼
也就是說類 A
, 對 SuperA
有依賴, 那麼其餘類在 with
類 A
的時候, 必須繼承或者實現 SuperA
類
class B extends SuperA with A{
}
複製代碼
從中咱們能夠看出 mixin
機制對複用代碼提供了很是大的便利和靈活性
關於 Dart 面向對象就先分析到這裏
stackoverflow.com/questions/1…
stackoverflow.com/questions/4…
下面是個人公衆號,乾貨文章不錯過,有須要的能夠關注下,有任何問題能夠聯繫我: