級(jí)別: ★☆☆☆☆
標(biāo)簽:「Flutter 」「Dart」「Dart class」「Dart mixin」「Dart override」
作者: WYW
審校: QiShare團(tuán)隊(duì)
前言:
4篇Dart基礎(chǔ)已經(jīng)全部更新完成。目錄如下:
Dart 基礎(chǔ) (一)
Dart 基礎(chǔ) (二)
Dart 基礎(chǔ) (三)
Dart 基礎(chǔ) (四)
筆者在本文中主要會(huì)分享:類(lèi)、實(shí)例變量、構(gòu)造方法、命名構(gòu)造方法、實(shí)例方法、靜態(tài)變量、靜態(tài)方法、set、get 方法、extends
、implements
、mixin
、abstract
、override
相關(guān)的內(nèi)容。
1.類(lèi)
下邊筆者先以Point 類(lèi)為例,分享下關(guān)于實(shí)例變量
,構(gòu)造方法
,命名構(gòu)造方法
,實(shí)例方法
、靜態(tài)方法
、 靜態(tài)變量
、set get方法
的內(nèi)容。
Dart 是一種面向?qū)ο蟮木幊陶Z(yǔ)言,同時(shí)支持基于 mixin 的繼承機(jī)制。mixin相關(guān)的內(nèi)容會(huì)在下文解釋。每個(gè)對(duì)象都是一個(gè)類(lèi)的實(shí)例,所有的類(lèi)都繼承于 Object。 基于 Mixin 的繼承 意味著每個(gè)類(lèi)(Object 除外) 都只有一個(gè)超類(lèi),一個(gè)類(lèi)的代碼可以在其他 多個(gè)類(lèi)繼承中重復(fù)使用。
使用 new 關(guān)鍵字和構(gòu)造方法來(lái)創(chuàng)建新的對(duì)象。 構(gòu)造方法名字可以為 ClassName 或者 ClassName.identifier。
在Dart2.0的時(shí)候,創(chuàng)建新的對(duì)象的時(shí)候,new 關(guān)鍵字是可選的。當(dāng)前Dart最新版本是2.4.0,2019-06-27 Dart開(kāi)發(fā)團(tuán)隊(duì)發(fā)布2.4.0版本Dart。 Dart change log
1.1 實(shí)例變量
class Point {
// 實(shí)例變量
num x;
num y;
}
1.2 構(gòu)造方法:構(gòu)造方法 定義一個(gè)和類(lèi)名一樣的方法
// 構(gòu)造方法 定義一個(gè)和類(lèi)名一樣的方法
Point(num x, num y) {
// this 關(guān)鍵字指當(dāng)前的實(shí)例
this.x = x;
this.y = y;
}
// 由于把構(gòu)造方法參數(shù)賦值給實(shí)例變量的場(chǎng)景太常見(jiàn)了, Dart 提供了一個(gè)語(yǔ)法糖來(lái)簡(jiǎn)化這個(gè)操作
// Point(this.x, this.y);
1.3 命名構(gòu)造方法
// 命名構(gòu)造方法
Point.fromJson(Map json) {
// 只有當(dāng)名字沖突的時(shí)候才使用 this。否則的話(huà), Dart 代碼風(fēng)格樣式推薦忽略 this。
x = json['x'];
y = json['y'];
}
Point.namedConstructor(Map json){
x = json['x'];
y = json['y'];
}
命名構(gòu)造方法使用場(chǎng)景有:模型類(lèi)中解析數(shù)據(jù)場(chǎng)景。
舉個(gè)簡(jiǎn)單例子:如返回一個(gè)列表數(shù)據(jù)的情況,返回?cái)?shù)據(jù)可能是是一個(gè)包著多個(gè)字典的數(shù)組,那么,處理相應(yīng)數(shù)據(jù)的時(shí)候,需要對(duì)數(shù)據(jù)進(jìn)行相應(yīng)的解析。解析的過(guò)程就可能用到命名構(gòu)造方法。把一個(gè)個(gè)字典當(dāng)做實(shí)例,提取出來(lái)。
[
{
"name":"QiShare1",
"age":"1"
},
{
"name":"QiShare2",
"age":"1"
},
{
"name":"QiShare3",
"age":"1"
},
{
"name":"QiShare4",
"age":"1"
},
{
"name":"QiShare5",
"age":"1"
},
{
"name":"QiShare6",
"age":"1"
},
{
"name":"QiShare7",
"age":"1"
},
]
1.4 實(shí)例方法
// 實(shí)例方法
num distanceTo(Point other) {
var dx = x - other.x;
var dy = y - other.y;
return sqrt(dx*dx + dy*dy);
}
1.5 靜態(tài)方法
使用static關(guān)鍵字修飾的方法為靜態(tài)方法,相當(dāng)于類(lèi)方法。使用類(lèi)名可以直接調(diào)用。
// 靜態(tài)方法
static num distanceBetween(Point a, Point b) {
var dx = a.x - b.x;
var dy = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}
void classDemo() {
var jsonData = jsonDecode('{"x":2, "y":2}');
// Create a Point using Point().
var p1 = new Point(1, 1);
print('p1點(diǎn)x坐標(biāo):${p1.x}');
print('p1點(diǎn)y坐標(biāo):${p1.y}');
// Create a Point using Point.fromJson().
var p2 = new Point.fromJson(jsonData);
print('p2點(diǎn)x坐標(biāo):${p2.x}');
print('p2點(diǎn)y坐標(biāo):${p2.y}');
num distance = p2.distanceTo(p1);
print('p1到p2的距離: $distance');
Map jsonData3 = {
'x': 3,
'y': 3,
};
Point p3 = Point.namedConstructor(jsonData3);
print('p3點(diǎn)x坐標(biāo):${p3.x}');
print('p3點(diǎn)y坐標(biāo):${p3.y}');
num distance12 = Point.distanceBetween(p1, p2);
print('p1和p2之間的距離 $distance12');
}
輸出內(nèi)容
flutter: p1點(diǎn)x坐標(biāo):1
flutter: p1點(diǎn)y坐標(biāo):1
flutter: p2點(diǎn)x坐標(biāo):2
flutter: p2點(diǎn)y坐標(biāo):2
flutter: p1到p2的距離: 1.4142135623730951
flutter: p3點(diǎn)x坐標(biāo):3
flutter: p3點(diǎn)y坐標(biāo):3
flutter: p1和p2之間的距離 1.4142135623730951
1.6 靜態(tài)變量
靜態(tài)變量對(duì)于類(lèi)級(jí)別的狀態(tài)是非常有用的,筆者對(duì)這句話(huà)的理解是:靜態(tài)變量可以由類(lèi)名直接調(diào)用。
class Color {
static const red =
const Color('red'); // A constant static variable.
final String name; // An instance variable.
const Color(this.name); // A constant constructor.
}
使用方式
String colorName = Color.red.name;
print('colorName:$colorName');
輸出內(nèi)容
colorName:red`
1.7 set get 方法
下邊筆者舉了一個(gè)類(lèi)Rectangle的left、top、width、height的Set、Get方法的例子。
class Rectangle {
num left;
num top;
num width;
num height;
Rectangle(this.left, this.top, this.width, this.height);
// Define two calculated properties: 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;
}
使用方式
Rectangle rectangel = Rectangle(0, 0, 375, 667);
print('rectangel.left:');
print(rectangel.left);
print('rectangel.right:');
print(rectangel.right);
print('rectangel.width:');
print(rectangel.width);
print('rectangel.height:');
print(rectangel.height);
print('rectangel.right:');
print(rectangel.right);
print('rectangel.bottom:');
print(rectangel.bottom);
輸出結(jié)果:
flutter: rectangel.left:
flutter: 0
flutter: rectangel.right:
flutter: 375
flutter: rectangel.width:
flutter: 375
flutter: rectangel.height:
flutter: 667
flutter: rectangel.right:
flutter: 375
flutter: rectangel.bottom:
flutter: 667
2. extends 與 implements
extends
關(guān)鍵字extends 用于繼承父類(lèi)的實(shí)例變量及方法等。Dart 只支持單繼承。
implements
Every class implicitly defines an interface containing all the instance members of the class and of any interfaces it implements. If you want to create a class A that supports class B’s API without inheriting B’s implementation, class A should implement the B interface.
每個(gè)類(lèi)都隱式地聲明了一個(gè)包含所有的實(shí)例變量和類(lèi)已經(jīng)實(shí)現(xiàn)的接口。
如果你想創(chuàng)建一個(gè)類(lèi)A,沒(méi)有繼承類(lèi)B,但是類(lèi)A可訪問(wèn)類(lèi)B的API,那么類(lèi)A 應(yīng)該實(shí)現(xiàn)類(lèi)B的接口。
上邊的內(nèi)容,結(jié)合著下邊的例子,筆者的理解是:Chicken隱式地聲明了Animal 的實(shí)例變量,和類(lèi)Animal 已經(jīng)實(shí)現(xiàn)的方法。Chicken支持在沒(méi)有繼承類(lèi)Animal的情況下,可訪問(wèn)類(lèi)B的API。
一個(gè)類(lèi)可以implements 多個(gè)類(lèi)的API,所以implements算是一種變向?qū)崿F(xiàn)多繼承的方式。
class Animal {
String name;
void ability() {
print('Animal 的能力');
}
}
class Bird extends Animal {
void ability(){
print('bird can fly');
}
}
class Fish extends Animal {
void ability(){
print('fish can swim');
}
}
class Dog extends Animal {
void ability(){
print('dog can bark');
}
}
class Chicken implements Animal {
String name;
void ability() {
print('chicken can lay eggs');
}
}
調(diào)用如上代碼的方式及相應(yīng)輸出結(jié)果如下:
Dog dog = Dog();
dog.ability();
Fish fish = Fish();
fish.ability();
Bird bird = Bird();
bird.ability();
Chicken chicken = Chicken();
chicken.ability();
// 輸出結(jié)果:
flutter: dog can bark
flutter: fish can swim
flutter: bird can fly
flutter: chicken can lay eggs
3. mixin
Mixins 是一種在多類(lèi)繼承中重用一個(gè)類(lèi)代碼的方法。筆者的理解是,mixin相當(dāng)于是一個(gè)工具類(lèi),使用
with
關(guān)鍵字使用了mixin的類(lèi),就可以使用mixin中的代碼。
Mixins are a way of reusing a class’s code in multiple class hierarchies.
To use a mixin, use the with keyword followed by one or more mixin names. The following example shows two classes that use mixins:
Mixin 是一種在多個(gè)類(lèi)中重用某些代碼的方式。
使用mixin ,需使用with
關(guān)鍵字,with后邊跟mixin的名,with 后邊可以跟多個(gè)mixin名字,及可以同時(shí)使用多個(gè)mixin中的代碼。下邊筆者舉了一個(gè)開(kāi)發(fā)者學(xué)習(xí)基礎(chǔ)語(yǔ)言的例子。筆者定義了一個(gè)Developer的mixin,如果是iOS 開(kāi)發(fā)者需要先學(xué)習(xí)C語(yǔ)言基礎(chǔ),如果是Android 開(kāi)發(fā)者,需要先學(xué)習(xí)Java語(yǔ)言,如果是Flutter 開(kāi)發(fā)者,需要先學(xué)習(xí)Dart 語(yǔ)言。
mixin Developer {
bool isIOS = false;
bool isAndroid = false;
bool isFlutter = false;
// 需要學(xué)習(xí)的基礎(chǔ)語(yǔ)言
void needLearnBaseProgram () {
if (isIOS) {
print('Need Learn C Firstly');
} else if (isAndroid) {
print('Need Learn Java Firstly');
} else if (isFlutter) {
print('Need Learn Dart Firstly');
} else {
print('May be need Learn Other Language');
}
}
}
class FlutterDeveloper with Developer {
String name;
FlutterDeveloper(String name) {
isFlutter = true;
this.name = name;
}
}
使用的相關(guān)代碼:
FlutterDeveloper flutterDeveloper = FlutterDeveloper('FlutterEnginerName');
flutterDeveloper.needLearnBaseProgram();
// 輸出結(jié)果: flutter: Need Learn Dart Firstly
注意事項(xiàng): 當(dāng)在if else 場(chǎng)景下使用 bool 類(lèi)型變量的時(shí)候,需要注意bool變量是否賦值過(guò)了,否則會(huì)有類(lèi)似如下的異常信息。
flutter: The following assertion was thrown while handling a gesture:
flutter: Failed assertion: boolean expression must not be null
4. abstract
使用 abstract 修飾的類(lèi) 記為抽象類(lèi)。抽象類(lèi)用于定義接口 及部分實(shí)現(xiàn)。
筆者舉了如下例子:
創(chuàng)建了People 類(lèi),并且聲明了 String skinColor();的抽象方法,創(chuàng)建并實(shí)現(xiàn)了 void ability() 方法;
abstract class People {
String skinColor();
void ability() {
print('All can Communicate');
}
}
class YellowPeople extends People {
@override
String skinColor() {
String color = 'Yellow';
print(color);
return color;
}
}
class BlackPeople extends People {
@override
skinColor() {
String color = 'black';
print(color);
return color;
}
}
class WhitePeople extends People {
@override
skinColor() {
String color = 'White';
print(color);
return color;
}
}
下邊是使用示例,及相應(yīng)的輸出結(jié)果。
YellowPeople yellowPeople = YellowPeople();
yellowPeople.ability();
yellowPeople.skinColor();
WhitePeople whitePeople = WhitePeople();
whitePeople.ability();
whitePeople.skinColor();
BlackPeople blackPeople = BlackPeople();
blackPeople.ability();
blackPeople.skinColor();
// 輸出結(jié)果:
flutter: All can Communicate
flutter: Yellow
flutter: All can Communicate
flutter: White
flutter: All can Communicate
flutter: black
- 抽象類(lèi)不能創(chuàng)建實(shí)例。
- 抽象方法為沒(méi)有方法體的方法。只有抽象類(lèi)中可以寫(xiě)抽象方法,其他普通類(lèi)不可以。
- 例:如果BlackPeople的skinColor 沒(méi)有方法體即沒(méi)有實(shí)現(xiàn),則會(huì)報(bào)錯(cuò)如下:'skinColor' must have a method body because 'BlackPeople' isn't abstract.
Try making 'BlackPeople' abstract, or adding a body to 'skinColor'.
- 例:如果BlackPeople的skinColor 沒(méi)有方法體即沒(méi)有實(shí)現(xiàn),則會(huì)報(bào)錯(cuò)如下:'skinColor' must have a method body because 'BlackPeople' isn't abstract.
- 繼承了抽象類(lèi)的子類(lèi)必須實(shí)現(xiàn)抽象方法
- 以WhitePeople 為例,如果不實(shí)現(xiàn)skinColor 方法會(huì)報(bào)出如下錯(cuò)誤:
- Missing concrete implementation of People.skinColor.
- Try implementing the missing method, or make the class abstract.
- 以WhitePeople 為例,如果不實(shí)現(xiàn)skinColor 方法會(huì)報(bào)出如下錯(cuò)誤:
5. override
"5.1 override 運(yùn)算符"及override toString
這里筆者對(duì)override 運(yùn)算符添加了引號(hào)。至于原因,等大家看完了下邊的內(nèi)容之后,便會(huì)了解筆者的用意。下文提到的override和重寫(xiě)是一個(gè)意思。
先看下運(yùn)算符重寫(xiě)的示例代碼:
Vector 類(lèi),重寫(xiě)了+ 運(yùn)算符和減運(yùn)算符,以達(dá)到Vector可以直接進(jìn)行加減的目的。筆者還重寫(xiě)了Vector類(lèi)的toString 方法,便于查看Vector的x、y值。
class Vector {
final int x;
final int y;
const Vector(this.x, this.y);
Vector operator +(Vector v) {
return Vector(x + v.x, y + v.y);
}
Vector operator -(Vector v) {
return Vector(x - v.x, y - v.y);
}
@override
String toString() {
return 'runtimeType:' + this.runtimeType.toString() + ',x:' + x.toString() +',y:' + y.toString();
}
}
使用Vector的+、-運(yùn)算符,及重寫(xiě)toString后,使用Vector的示例代碼及輸出結(jié)果如下:
Vector v1 = Vector(1, 1);
Vector v2 = Vector(2, 2);
Vector v3 = v1 + v2;
Vector v0 = v2 - v1;
print(v0);
print(v3);
// 輸出結(jié)果:
flutter: runtimeType:Vector,x:1,y:1
flutter: runtimeType:Vector,x:3,y:3
重寫(xiě)toString的效果是:可控制print的對(duì)象的內(nèi)容及格式。這一點(diǎn)便于非調(diào)試環(huán)境下查看一些具體錯(cuò)誤信息。
上文筆者提到了重寫(xiě)運(yùn)算符是加引號(hào)的原因如下:在筆者看來(lái),運(yùn)算符的重寫(xiě)有點(diǎn)跑題了。重寫(xiě)toString才算是重寫(xiě)。重寫(xiě)的toString的返回值、方法名和參數(shù)和父類(lèi)Object都一樣。如大家有不同理解,歡迎討論。
參考學(xué)習(xí)網(wǎng)址
- http://dart.goodev.org/guides/language/language-tour#classes
- https://dart.dev/guides/language/language-tour#classes
推薦文章:
Dart基礎(chǔ)(一)
Dart基礎(chǔ)(二)
Dart基礎(chǔ)(三)
iOS 短信驗(yàn)證碼倒計(jì)時(shí)按鈕
iOS 環(huán)境變量配置
iOS 中處理定時(shí)任務(wù)的常用方法
算法小專(zhuān)欄:貪心算法
iOS 快速實(shí)現(xiàn)分頁(yè)界面的搭建
iOS 中的界面旋轉(zhuǎn)