面向?qū)ο筇匦?/h4>
1.類(class )
Dart是一個面向?qū)ο缶幊陶Z言踪危,同時支持基于mixin的繼承機(jī)制雇寇。每個對象都是一個類的實(shí)例黍少,所有的類都繼承于object行剂。
1)構(gòu)造函數(shù)
構(gòu)造函數(shù)不能繼承。父類的命名構(gòu)造函數(shù)也不會被繼承,如果子類也有父類一樣命名構(gòu)造函數(shù)漾根,就必須在子類中自己實(shí)現(xiàn)該構(gòu)造函數(shù)泰涂。
- 默認(rèn)構(gòu)造函數(shù):如果未顯式定義構(gòu)造函數(shù),會默認(rèn)一個參數(shù)為空的構(gòu)造函數(shù)立叛。默認(rèn)構(gòu)造函數(shù)會調(diào)用父類的無參構(gòu)造函數(shù)负敏。
class Person { //未定義父類的時候贡茅,默認(rèn)繼承自O(shè)bject
num x;
num y;
num z;
}
void main(List<String> args){
var person = new Person();//調(diào)用默認(rèn)的構(gòu)造函數(shù)
person.x = 10; //使用點(diǎn)(.)引用實(shí)例變量或方法
person.y = 11;
}
- 類名構(gòu)造函數(shù):就是一個與類同名的函數(shù)秘蛇,關(guān)鍵字 this 是指當(dāng)前實(shí)例,只有在命名沖突時有效顶考,否則dart會忽略處理赁还。
class Point {
int x;
int y;
//自己定義的類名構(gòu)造函數(shù)
Point(int x, int y) {
this.x = x;
this.y = y;
}
// 在構(gòu)造函數(shù)里初始化成員屬性是很常見的事情,因此Dart開發(fā)了新的語法糖來簡化這種操作
// 比如將Point的類名構(gòu)造構(gòu)造函數(shù)改寫成
// Point(this.x, this.y);
// 注意x,y的賦值會在構(gòu)造函數(shù)執(zhí)行之前完成.
}
void main(){
var point = new Point(1, 2);
}
- 命名構(gòu)造函數(shù):(類名.函數(shù)名)使用命名構(gòu)造函數(shù)可以為類提供多個構(gòu)造函數(shù)驹沿。
class Point {
num x, y;
Point(this.x, this.y);
// 命名構(gòu)造函數(shù)
Point.origin() {
x = 0;
y = 0;
}
// 簡化
// Point.origin(this.x,this.y);
}
- 重定向構(gòu)造函數(shù):有時構(gòu)造函數(shù)的唯一目的是重定向到同一類中的另一個構(gòu)造函數(shù)艘策。重定向構(gòu)造函數(shù)的主體為空,構(gòu)造函數(shù)調(diào)用出現(xiàn)在冒號( :)之后 渊季。
大意就是在創(chuàng)建類時朋蔫,我定義一個命名構(gòu)造函數(shù),但是這個構(gòu)造函式的主體我不實(shí)現(xiàn)却汉。直接通過:調(diào)用另外一個構(gòu)造函數(shù)驯妄,實(shí)現(xiàn)對外界傳入的參數(shù)的接收并賦值給內(nèi)部的變量。
class Point {
num x, y;
//類名構(gòu)造函數(shù)
Point(this.x, this.y);
// 命名構(gòu)造函數(shù)
Point.order(this.x,this.y);
Point.origin(num a,num b):this.order(a,b);
//重定向構(gòu)造函數(shù)合砂,origin構(gòu)造函數(shù)將外界的傳值青扔,指向給了order構(gòu)造函數(shù)。
}
- 工廠構(gòu)造函數(shù):在實(shí)現(xiàn)一個構(gòu)造函數(shù)時使用factory關(guān)鍵字翩伪,該構(gòu)造函數(shù)并不總是創(chuàng)建其類的新實(shí)例微猖。例如,工廠構(gòu)造函數(shù)可能會從緩存中返回實(shí)例缘屹,也可能會返回子類型的實(shí)例凛剥。工廠構(gòu)造者對this沒有訪問權(quán)限。
class Logger {
final String name;
bool mute = false;
// _cache是私有變量
//_在名稱前轻姿,表示該變量為私有
static final Map<String, Logger> _cache = <String, Logger>{};
factory Logger(String name) {
if (_cache.containsKey(name)) {
return _cache[name];
} else {
final logger = Logger._internal(name);
_cache[name] = logger;
return logger;
}
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
調(diào)用:
var logger = Logger('UI');
logger.log('Button clicked');
- 常量構(gòu)造函數(shù):如果你的類創(chuàng)建的對象從不改變当悔,你可以創(chuàng)建一些編譯時的常量對象。因此踢代,定義一個const構(gòu)造函數(shù)盲憎,且保證所有的對象變量都是final。
class ImmutablePoint {
final num x;
final num y;
const ImmutablePoint(this.x, this.y);
static final ImmutablePoint origin =
const ImmutablePoint(0, 0);
}
注意:如果父類中沒有默認(rèn)的構(gòu)造函數(shù)胳挎,你必須手動調(diào)用父類的構(gòu)造函數(shù)饼疙,在子類的構(gòu)造函數(shù)體之前通過(:) 指定調(diào)用父類構(gòu)造函數(shù),示例如下:
// Person類中沒有一個無參數(shù),未命名的構(gòu)造函數(shù)
class Person {
String firstName;
// 命名構(gòu)造函數(shù)
Person.fromJson(Map data) {
print('in Person');
}
}
class Employee extends Person {
// 你必須調(diào)用父類的super.fromJson(data).
Employee.fromJson(Map data) : super.fromJson(data) {
print('in Employee');
}
}
main() {
var emp = new Employee.fromJson({});
}
2.實(shí)例變量
聲明實(shí)例變量時窑眯,所有未初始化的實(shí)例變量的值為null屏积。
每個實(shí)例變量都會自動生成一個getter方法,Non-final(沒有被final修飾)實(shí)例變量還會自定生成一個setter方法。
class Point{
num x;//聲明實(shí)例變量x磅甩,初始化為空
num y;//聲明實(shí)例變量y炊林,舒適化為空
num z = 0;//聲明實(shí)例變量z,初始化為0
//如果在實(shí)例變量定義的時候初始化該變量(不是在構(gòu)造函數(shù)或者其他方法中初始化)卷要,該值是在實(shí)例化對象的時
//候初始化的渣聚,也就是在構(gòu)造函數(shù)和初始化參數(shù)列表執(zhí)行之前。
}
void main() {
var point = new Point();
point.x = 4; //使用setter方法對x變量賦值
print(point.x == 4); //輸出true 使用getter獲取x變量的值
print(point.y == null); //輸出true
}
靜態(tài)(類)變量:使用static關(guān)鍵字來實(shí)現(xiàn)類級別的變量和方法僧叉,靜態(tài)函數(shù)內(nèi)部不能訪問非靜態(tài)成員奕枝,非靜態(tài)函數(shù)能訪問靜態(tài)成員。
class Queue {
// 靜態(tài)變量在使用之前不會初始化
static const initialCapacity = 16;
// ···
}
void main() {
assert(Queue.initialCapacity == 16);
}
3.方法
1)實(shí)例方法
對象的實(shí)例函數(shù)可以訪問this瓶堕。
import 'dart:math';
class Point {
num x;
num y;
Point(this.x, this.y);
num distanceTo(Point other) {
var dx = x - other.x;
var dy = y - other.y;
return sqrt(dx * dx + dy * dy);
}
}
2)類方法
使用static 修飾的方法隘道,內(nèi)部不能訪問實(shí)例變量,沒有訪問this的權(quán)限。
class Page{
// 添加 static 關(guān)鍵字
static int currentPage = 1;
num size ;
//類方法
static void scorllDown(){
currentPage = 1;
// 訪問實(shí)例變量報錯
// size = 10;
print("ScrollDown...");
}
void scorllUp(){
currentPage ++;
print("ScrollUp...");
}
}
void main(List<String> args) {
var page = new Page();
// 調(diào)用類方法
Page.scorllDown();
}
3)Getters和Setters 方法
Getters 和setters是用來設(shè)置和訪問對象屬性的特殊函數(shù)郎笆。每個實(shí)例變量都隱含的具有一個getter谭梗,如果變量不是final的則還有一個setter。使用get和set關(guān)鍵字定義getter和setter宛蚓。
class Rectangle {
num left;
num top;
num width;
num height;
Rectangle(this.left, this.top, this.width, this.height);
// 定義兩個計(jì)算屬性:右和下激捏。
num get right => left + width;
set right(num value) => left = value - width;
num get bottom => top + height;
set bottom(num value) => top = value - height;
}
main() {
var rect = new Rectangle(3, 4, 20, 15);
assert(rect.left == 3);
rect.right = 12;
assert(rect.left == -8);
}
4)抽象函數(shù)
抽象函數(shù)是只定義函數(shù)接口但是沒有實(shí)現(xiàn)的函數(shù),由子類來實(shí)現(xiàn)該函數(shù)苍息。如果用分號來替代函數(shù)體則這個函數(shù)就是抽象函數(shù)缩幸。
abstract class Doer {
// ...定義實(shí)例變量和方法...
void doSomething(); // 定義一個抽象方法.
}
class EffectiveDoer extends Doer {
void doSomething() {
// ...提供實(shí)現(xiàn),因此此處的方法不是抽象的...
}
}
4.抽象類
使用abstract修飾符定義一個抽象類竞思,一個不能被實(shí)例化的類表谊。抽象類通常用來定義接口,如果你想實(shí)例化抽象類盖喷,你必須實(shí)現(xiàn)抽象類爆办,才能被實(shí)例化。
// 這個類是抽象類课梳,不能實(shí)例化
abstract class AbstractContainer {
// ...定義構(gòu)造函數(shù), 變量, 方法...
void updateChildren(); // 抽象方法.
}
class SpecializedContainer extends AbstractContainer {
// ...定義更多的構(gòu)造方法, 方法...
void updateChildren() {
// ...實(shí)現(xiàn) updateChildren()...
}
}
5.隱式接口
Dart中沒有哪個關(guān)鍵字是來定義接口的距辆, 默認(rèn)情況下所有的類類都是都是隱式的接口,包括類的方法和屬性暮刃。當(dāng)將一個類當(dāng)做接口使用時跨算,那么實(shí)現(xiàn)這個接口的類,必須實(shí)現(xiàn)這個接口中所有的方法椭懊。
// A person. 隱式接口包含greet().
class Person {
// 在接口中诸蚕,但僅在此庫中可見
final _name;
// 不在接口中,因?yàn)檫@是構(gòu)造函數(shù)
Person(this._name);
// 在接口中
String greet(who) => 'Hello, $who. I am $_name.';
}
// 實(shí)現(xiàn)Person 接口
class Imposter implements Person {
// 我們必須定義這個,但我們不使用它背犯。
final _name = "";
String greet(who) => 'Hi $who. Do you know who I am?';
}
6.類的繼承
使用extends創(chuàng)建子類坏瘩,super引用父類,子類可以重寫實(shí)例方法漠魏、getter和setter倔矾,使用@override注釋重寫,使用@proxy注釋來忽略警告
class Person {
void run{
print('people run');
}
}
class Kids{
@override
void run{
print('Kids run');
}
}
重寫object的noSuchMethod()
當(dāng)用戶調(diào)用你定義的類中不存在的屬性與方法時柱锹,通過重寫noSuchMethod(),可以做出一些響應(yīng)哪自。
class A {
@override
void noSuchMethod(Invocation invocation) {
print('You tried to use a non-existent member: ' +
'${invocation.memberName}');
}
}
7.訪問控制
默認(rèn)類中的所有屬性和方法是public的。在dart中奕纫,可以在屬性和方法名前添加“_”使私有化提陶。
class Animal{
String _name; // 私有屬性
int age;
//默認(rèn)構(gòu)造函數(shù)的簡寫
Animal(this._name,this.age);
void printInfo(){
print("${this._name}----${this.age}");
}
// 供外部調(diào)用私有屬性
String getName(){
return this._name;
}
// 私有方法
void _run(){
print('這是一個私有方法');
}
execRun(){
this._run(); //類里面方法的相互調(diào)用
}
}
void main(){
Animal a=new Animal('小狗', 3);
print(a.getName());
a.execRun(); //間接的調(diào)用私有方法
}
8.枚舉類型
枚舉中的每個值都有一個index索引烫沙,它返回枚舉聲明中值的從零開始的位置匹层。例如,第一個值具有索引0锌蓄,第二個值具有索引1升筏。
enum Color { red, green, blue }
assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);
可以在switch語句中使用枚舉,如果不處理枚舉的所有值,將會收到警告瘸爽。
9.泛型
泛型就是定義的一個類型您访,類型暫不確定,給使用給一個占位符給代替剪决,在使用的時候可以給確定其定義的類型灵汪。
main() {
// 如果自己希望List只包含字符串對象。則可以定義為List<String>代表("list of string")柑潦。
List Tech = new List<String>();
Tech.addAll(['Android','IOS','Flutter']);
Tech.add(42);//運(yùn)行時報錯
}