Dart - 類(變量聲明鹃愤、構造函數)

這節(jié)詳細介紹如何定義類的變量聲明構造方法挂洛。

實例變量

下面是聲明實例變量的示例:

class Point {
  num x; // 聲明實例變量 x 并初始化為 null。
  num y; // 聲明實例變量 y 并初始化為 null。
  num z = 0; // 聲明實例變量 z 并初始化為 0卜朗。
}

備忘:"所有未初始化的實例變量其值均為 null熬的。"

所有實例變量均會隱式地聲明一個 Getter 方法,非 final 類型的實例變量還會隱式地聲明一個 Setter 方法拌喉。你可以查閱 Getter 和 Setter 速那。

class Point {
  num x;
  num y;
}

void main() {
  var point = Point();
  point.x = 4; // 使用 x 的 Setter 方法。
  assert(point.x == 4); // 使用 x 的 Getter 方法尿背。
  assert(point.y == null); // 默認值為 null端仰。
}

備忘:
如果你在聲明一個實例變量的時候就將其初始化(而不是在構造函數或其它方法中),那么該實例變量的值就會在對象實例創(chuàng)建的時候被設置田藐,該過程會在構造函數以及它的初始化器列表執(zhí)行前荔烧。

構造函數

聲明一個與類名一樣的函數即可聲明一個構造函數(對于命名式構造函數還可以添加額外的標識符)。大部分的構造函數形式是生成式構造函數汽久,其用于創(chuàng)建一個類的實例:

class Point {
  num x, y;

  Point(num x, num y) {
    // 還會有更好的方式來實現此邏輯鹤竭,敬請期待。
    this.x = x;
    this.y = y;
  }
}

當且僅當命名沖突時使用 this 關鍵字才有意義景醇,否則 Dart 會忽略 this 關鍵字臀稚。

對于大多數編程語言來說在構造函數中為實例變量賦值的過程都是類似的,而 Dart 則提供了一種特殊的語法糖來簡化該步驟:

class Point {
  num x, y;

  // 在構造函數體執(zhí)行前用于設置 x 和 y 的語法糖三痰。
  Point(this.x, this.y);
}

這種用類名加變量的聲明構造方法只能有一個吧寺,那么如何定義多個構造方法呢?先帶著疑問散劫,繼續(xù)往下看稚机。

默認構造函數

如果你沒有聲明構造函數,那么 Dart 會自動生成一個無參數的構造函數并且該構造函數會調用其父類的無參數構造方法获搏。

構造函數不會被繼承

子類不會繼承父類的構造函數赖条,如果子類沒有聲明構造函數,那么只會有一個默認無參數的構造函數颜凯。

命名式構造函數

可以為一個類聲明多個命名式構造函數來表達更明確的意圖:

class Point {
 num x, y;

 Point(this.x, this.y);

 // 命名式構造函數
 Point.origin() {
   x = 0;
   y = 0;
 }
}

跟構造函數的語法糖一樣谋币,也可以寫成:

class Point {
  num x, y;

  Point(this.x, this.y);

  // 命名式構造函數
  Point.origin(this.x, this.y) ;
}

備忘:

    1. 記住構造函數是不能被繼承的,這將意味著子類不能繼承父類的命名式構造函數症概,如果你想在子類中提供一個與父類命名構造函數名字一樣的命名構造函數蕾额,則需要在子類中顯式地聲明。
    1. 如果聲明有參構造函數彼城,這時就沒有無參構造函數诅蝶,也無法顯示聲明退个,因為類型構造函數只有一個;如果你聲明了命名式的構造函數调炬,這時就沒有無參構造函數了语盈,但你可以顯示地聲明出來。
    1. 第1點不能函數名重名的原因是:C++ 與 Java 的做法是缰泡,提供函數的重載刀荒,即提供同名但參數不同的函數。但 Dart 認為重載會導致混亂棘钞,因此從設計之初就不支持重載缠借,而是提供了可選命名參數和可選參數。

調用父類非默認構造函數

默認情況下宜猜,子類的構造函數會調用父類的匿名無參數構造方法泼返,并且該調用會在子類構造函數的函數體代碼執(zhí)行前,如果子類構造函數還有一個初始化列表姨拥,那么該初始化列表會在調用父類的該構造函數之前被執(zhí)行绅喉,總的來說,這三者的調用順序如下:

    1. 初始化列表
    1. 父類的無參數構造函數
    1. 當前類的構造函數

如果父類沒有匿名無參數構造函數叫乌,那么子類必須調用父類的其中一個構造函數柴罐,為子類的構造函數指定一個父類的構造函數只需在構造函數體前使用(:)指定。

class Person {
  String firstName;

  Person.fromJson(Map data) {
    print('in Person');
  }
}

class Employee extends Person {
  // Person does not have a default constructor;
  // you must call super.fromJson(data).
  Employee.fromJson(Map data) : super.fromJson(data) {
    print('in Employee');
  }
}

main() {
  var emp = new Employee.fromJson({});

  // Prints:
  // in Person
  // in Employee
  if (emp is Person) {
    // Type check
    emp.firstName = 'Bob';
  }
  (emp as Person).firstName = 'Bob';
}

備忘:
"父類沒有匿名無參數構造函數综芥,那么子類必須調用父類的其中一個構造函數"

因為參數會在子類構造函數被執(zhí)行前傳遞給父類的構造函數丽蝎,因此該參數也可以是一個表達式,比如一個函數:

class Employee extends Person {
  Employee() : super.fromJson(defaultData);
  // ···
}

class Employee extends Person {
  Employee() : super();
  // ···
}

備忘:

    1. 構造函數聲明主體后面接:可以調用父類的構造方法膀藐,用super代替父類的類型屠阻,如super()super.fromJson()额各,用this可以接本類的其他構造方法国觉,很常用很強大,要記住虾啦。
    1. 傳遞給父類構造函數的參數不能使用this關鍵字麻诀,因為在參數傳遞的這一步驟,子類構造函數尚未執(zhí)行傲醉,子類的實例對象也就還未初始化蝇闭,因此所有的實例成員都不能被訪問,但是類成員可以硬毕。
    1. 構造函數聲明主體后面接:不僅僅是接父類構造函數呻引,還可以接表達式、初始化列表(下面會介紹)吐咳。

初始化列表

剛才我們提到初始化列表會在父類構造函數前執(zhí)行逻悠,到底什么是初始化列表元践?

//初始化列表必須在父類表達式聲明之前
Employee.fromJson(Map data) : employeeName = 'hahha',super(){
    print('in Employee');
  }

除了調用父類構造函數之外,還可以在構造函數體執(zhí)行之前初始化實例變量童谒,每個實例變量之間使用逗號分隔单旁,這就是初始化列表:

// 使用初始化列表在構造函數體執(zhí)行前設置實例變量。
Point.fromJson(Map<String, num> json)
    : x = json['x'],
      y = json['y'] {
  print('In Point.fromJson(): ($x, $y)');
}

初始化列表表達式 = 右邊的語句不能使用 this 關鍵字饥伊。

初始化列表用來設置final字段是非常好用的象浑,下面的示例中就使用初始化列表來設置了三個final 變量的值。

import 'dart:math';

class Point {
  final num x;
  final num y;
  final num distanceFromOrigin;

  Point(x, y)
      : x = x,
        y = y,
        distanceFromOrigin = sqrt(x * x + y * y);
}

main() {
  var p = new Point(2, 3);
  print(p.distanceFromOrigin);
}

重定向構造函數

有時候類中的構造函數會調用類中其它的構造函數撵渡,該重定向構造函數沒有函數體融柬,只需在函數簽名后使用(:)指定需要重定向到的其它構造函數即可:

class Point {
  num x, y;

  // 該類的主構造函數。
  Point(this.x, this.y);

  // 委托實現給主構造函數趋距。
  Point.alongXAxis(num x) : this(x, 0);
}

這個語法糖和命名構造函數共同實現多個構造函數的實現,比起只用命名構造函數實現越除,委托實現可以幫忙實現重復的初始化代碼节腐。

委托后面不能再加大括號:

Employee.fromJson(Map data) : this();

常量構造函數

如果類生成的對象都是不會變的,那么可以在生成這些對象時就將其變?yōu)榫幾g時常量摘盆。你可以在類的構造函數前加上const關鍵字并確保所有實例變量均為final來實現該功能翼雀。

class ImmutablePoint {
  static final ImmutablePoint origin =
      const ImmutablePoint(0, 0);

  final num x, y;

  const ImmutablePoint(this.x, this.y);
}

工廠構造函數

使用factory關鍵字標識類的構造函數將會令該構造函數變?yōu)楣S構造函數,這將意味著使用該構造函數構造類的實例時并非總是會返回新的實例對象孩擂。例如狼渊,工廠構造函數可能會從緩存中返回一個實例,或者返回一個子類型的實例类垦。

以下示例演示了從緩存中返回對象的工廠構造函數:

class Logger {
  final String name;
  bool mute = false;

  // _cache 變量是庫私有的狈邑,因為在其名字前面有下劃線。
  static final Map<String, Logger> _cache =
      <String, Logger>{};

  factory Logger(String name) {
    return _cache.putIfAbsent(
        name, () => Logger._internal(name));
  }

  Logger._internal(this.name);

  void log(String msg) {
    if (!mute) print(msg);
  }
}

在工廠構造函數中無法訪問 this蚤认。

工廠構造函的調用方式與其他構造函數一樣:


var logger = Logger('UI');
logger.log('Button clicked');
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末米苹,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子砰琢,更是在濱河造成了極大的恐慌蘸嘶,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件陪汽,死亡現場離奇詭異训唱,居然都是意外死亡,警方通過查閱死者的電腦和手機挚冤,發(fā)現死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門况增,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人你辣,你說我怎么就攤上這事巡通〕局矗” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵宴凉,是天一觀的道長誊锭。 經常有香客問我,道長弥锄,這世上最難降的妖魔是什么丧靡? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮籽暇,結果婚禮上温治,老公的妹妹穿的比我還像新娘。我一直安慰自己戒悠,他們只是感情好熬荆,可當我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著绸狐,像睡著了一般卤恳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上寒矿,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天突琳,我揣著相機與錄音,去河邊找鬼符相。 笑死拆融,一個胖子當著我的面吹牛,可吹牛的內容都是我干的啊终。 我是一名探鬼主播镜豹,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼孕索!你這毒婦竟也來了逛艰?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤搞旭,失蹤者是張志新(化名)和其女友劉穎散怖,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體肄渗,經...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡镇眷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了翎嫡。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片欠动。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出具伍,到底是詐尸還是另有隱情翅雏,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布人芽,位于F島的核電站望几,受9級特大地震影響,放射性物質發(fā)生泄漏萤厅。R本人自食惡果不足惜橄抹,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望惕味。 院中可真熱鬧楼誓,春花似錦、人聲如沸名挥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽禀倔。三九已至阁猜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蹋艺,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工黄刚, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留捎谨,地道東北人。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓憔维,卻偏偏與公主長得像涛救,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子业扒,可洞房花燭夜當晚...
    茶點故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內容