[dart學習]第七篇:類(構造函數)


前言:樓主平時基本沒有使用過異常處理,所以對異常的認知可能不夠准確,這里就不翻譯異常的相關內容了,大家可以去官網自行閱讀介紹,地址 https://dart.dev/guides/language/language-tour#exceptions

我們前面提到,dart是面向對象的語言,程序中的每個對象都可以看作是某個類的實例。所有的類都派生自Object類。

(一)使用類的成員

與C++等面向對象語言一樣,dart的類成員包括方法(接口)與數據,使用點號操作符(.)可以訪問類的方法和數據。看個簡單例子:

//實例化Point類的一個對象,命名為p
var p = Point(2, 2);

// 設置類的成員y的值.
p.y = 3;

// 獲取成員y的值
assert(p.y == 3);

// 調用類的distanceTo方法
num distance = p.distanceTo(Point(4, 4));

一個小技巧: 使用 ?. 可以避免訪問一個空實例,如下例:

// If p is non-null, set its y value to 4.
p?.y = 4;

(二)構造器

了解C++的朋友都知道,在C++中類一定有構造函數,dart也是如此。

在dart中使用構造器創建一個對象,構造器可以是ClassName or ClassName.identifier,看以下例子:

// 使用 ClassName 創建
var p1 = Point(2, 2);
// 使用 ClassName.identifier 創建
var p2 = Point.fromJson({'x': 1, 'y': 2});

也可以使用 new 關鍵字創建,如下:

var p1 = new Point(2, 2);
var p2 = new Point.fromJson({'x': 1, 'y': 2});

以上兩段代碼的效果是一樣的。

(題外話:在C++中使用new創建的是指針,在這里我們看到,以上兩段代碼返回都是var類型)

可以使用const關鍵字創建編譯時常量的對象,簡單例子:

var a = const ImmutablePoint(1, 1);
var b = const ImmutablePoint(1, 1);

assert(identical(a, b)); // They are the same instance!

接着再看如下例子:

var a = const ImmutablePoint(1, 1); // Creates a constant
var b = ImmutablePoint(1, 1); // Does NOT create a constant

assert(!identical(a, b)); // NOT the same instance!

通過以上兩段代碼我們可以看出:即便構造器調用參數完全相同,const和非const對象也是不等同的。

(三)獲取一個對象的類型

可以調用對象的 runtimeType 屬性獲取對象的運行時數據類型, 該屬性是 Type 類型的對象。

print('The type of a is ${a.runtimeType}');

(四)實例變量

先看一個例子:

class Point {
  num x;        // 聲明實例變量x
  num y = 2;  // 聲明實例變量y
}
void main()
{
  var p = Point();        // 構造Point類的實例p
  print("y = ${p.y}");
  if(p.x == null)
  {
    print("p.x == null");
  }
  else
  {
    print("eeee");
  }
}    

代碼運行結果

通過上例我們可以看出:類中的變量默認被初始化為null,如果我們在類聲明時對變量進行了初始化(如Point類中的y),則該初始化賦值發生在調用構造函數之前

(五)構造函數

我們可以通過聲明一個與類名完全相同的函數來聲明構造函數(和C++一樣),當然,也可以選擇附加標識符,如 (二)構造器 一段所述。看個例子:

class Point {
  num x, y;

  Point(num x, num y) {
    // There's a better way to do this, stay tuned.
    this.x = x;
    this.y = y;
  }
}

 這里的this關鍵字指當前實例自身,另注:只在名字有沖突的時候才適用this關鍵字,否則可以省略。

(1)默認構造函數

前面已經提到,和C++一樣,如果你沒有聲明自己的構造函數,那么編譯器會給你提供一個默認的構造函數,默認構造函數無入參,並且調用父類的無參構造函數。

(2)構造函數不能繼承

子類不能繼承父類的構造函數。前面提到,子類如果沒有聲明構造函數,那么會有默認的構造函數,而不是集成父類的。

(3) 命名構造函數 (Named constructor)

看個例子:

class Point {
  num x, y;

  Point(this.x, this.y);

  // Named constructor
  Point.origin() {
    x = 0;
    y = 0;
  }
}

記住,構造函數不能繼承!如果想用父類中的命名構造函數創建一個子類,那你也必須在子類中實現這個命名構造函數!

(4) 構造函數的調用順序

子類的構造函數中執行的操作順序如下:

初始化列表->父類的無參構造函數->本類的無參構造函數。

如果父類沒有非命名、無參數的構造函數,那么你就必須手動調用父類的一個構造函數,在分號(:)后指明調用的父類構造函數,看以下例子:

class Person {
  String firstName;

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

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 Class');
  }
}

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

  // Prints:
  // in Person Class
  // in Employee Class
  if (emp is Person) {
    // Type check
    emp.firstName = 'Bob';
    print("emp is Person, firstname = ${emp.firstName}");
  }
  (emp as Person).firstName = 'Bob';
  print("Other,firstname = ${emp.firstName}");
}

以上代碼在vs code中運行結果如下:

父類構造函數的參數中無權限使用this關鍵字!

(5) 重定向構造函數

這個重定向構造函數,個人理解有一點點像C++里虛基的構造函數,重定向構造函數函數體為空,僅僅是在該類里用來重定向其他的構造函數的。看一個例子:

class Point {
  num x, y;

  // Point類的主構造函數,也是一個重定向構造函數,你看它的函數體是空的
  Point(this.x, this.y);

  // alongXAxis函數被重定向到Point執行構造處理
  Point.alongXAxis(num x) : this(x, 0);
}

(6)其他

官方對於構造函數還有一些其他類型的描述,如constant構造、factory構造等,本人對此不甚理解,因此這里就不做翻譯,大家有興趣請去官網閱讀相關說明。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM