7.Classes-類(Dart中文文檔)

来源:https://www.cnblogs.com/lowezheng/archive/2019/01/02/10186482.html
-Advertisement-
Play Games

Dart是一個面向對象的語言,同時增加了混入(mixin)繼承的特性。對象都是由類初始化生成的,所有的類都由Object對象繼承。混入繼承意味著儘管所有類(除了Object類)只有一個父類,但是類的代碼體可以在多個類中重覆使用。(個人理解:mixin,extends,implements,exte ...


Dart是一個面向對象的語言,同時增加了混入(mixin)繼承的特性。對象都是由類初始化生成的,所有的類都由Object對象繼承。混入繼承意味著儘管所有類(除了Object類)只有一個父類,但是類的代碼體可以在多個類中重覆使用。(個人理解:mixin,extends,implements,extends是類似java單繼承,implements類似java的多介面實現,但這些都是運行時使用,mixin應該是在編譯時使用,類似於jsp的include,比如 A with B,其實是在編譯時,將兩個類的代碼合併,編譯成classes) 。

Using class members 類成員

對象由成員變數和方法構成。你可以用點(.)調用方法或者成員變數

var p = Point(2, 2);

// Set the value of the instance variable y.
p.y = 3;

// Get the value of y.
assert(p.y == 3);

// Invoke distanceTo() on p.
num distance = p.distanceTo(Point(4, 4));
Use ?. instead of . to avoid an exception when the leftmost operand is null:

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

Using constructors 構造方法

你可以用構造方法創建對象,構造方法是ClassName或者ClassName.identifier.下麵是構造方法的兩種寫法:

Point() and Point.fromJson() constructors:

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

下麵的構造方法多了new關鍵字:

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

版本註意:new 關鍵字在Dart2中是可選的

一些類提供了靜態構造方法。當你需要這些創建編譯常量對象,可以在構造對象代碼前加上const關鍵字。

var p = const ImmutablePoint(2, 2);

兩個相同入參的編譯對象常量是相等。

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

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

在編譯常量上下中,可以忽略後續的const關鍵字,也可以達到同樣效果

// Lots of const keywords here.
const pointAndLine = const {
  'point': const [const ImmutablePoint(0, 0)],
  'line': const [const ImmutablePoint(1, 10), const ImmutablePoint(-2, 11)],
};

這是簡化的寫法:

// Only one const, which establishes the constant context.
const pointAndLine = {
  'point': [ImmutablePoint(0, 0)],
  'line': [ImmutablePoint(1, 10), ImmutablePoint(-2, 11)],
};

如果用常量構造器初始化對象,但是沒有加入const關鍵字,它將是非常量對象

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關鍵字的忽略寫法在Dart2中才有效

Getting an object’s type 獲取對象類型

在運行時獲取對象的類型,你可以用Object的對象的 runtimeType屬性。

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

Instance variables 成員變數

下麵是如何定義成員變數:

class Point {
  num x; // Declare instance variable x, initially null.
  num y; // Declare y, initially null.
  num z = 0; // Declare z, initially 0.
}

所有為初始化變數的值是null.

所有成員變數都內置get方法。非final的成員變數內置了set方法。

class Point {
  num x;
  num y;
}

void main() {
  var point = Point();
  point.x = 4; // Use the setter method for x.
  assert(point.x == 4); // Use the getter method for x.
  assert(point.y == null); // Values default to null.
}

如果你在成員變數的定義時就進行初始化,在對象創建時,它將先於構造器和初始化列表執行。

Constructors 構造器

類構造器是和類名同名的函數,(其中還有一種命名構造函數的寫法,後續介紹)。

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;
  }
}

上面的例子中,thisg關鍵字可以讀取成員變數。
註意:使用this只有在方法參數和成員變數有衝突時才用,其它場景可以不寫

如果構造器的入參和成員變數對應,可以直接賦值,可以用如下的簡化寫法:

class Point {
  num x, y;

  // Syntactic sugar for setting x and y
  // before the constructor body runs.
  Point(this.x, this.y);
}

Default constructors 預設構造器

如果沒有定義構造器,類將提供一個無參構造器,如果類有一個父類,也會調用父類的無參構造器

Constructors aren’t inherited 構造器不可繼承

子類不會繼承父類的構造器,如果子類沒有定義構造器,它只有預設的無參構造器,不會去繼承父類的構造器。

Named constructors 命名構造器

Dart可以使用命名構造器去實現多個構造邏輯。

class Point {
  num x, y;

  Point(this.x, this.y);

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

構造器是不可繼承的,這個規則在命名構造器同樣有效。如果你想要一個和父類一樣的命名構造器,需要在子類的自己定義同樣的構造器。

Invoking a non-default superclass constructor 調用父類的非預設構造器

預設情況下,子類的構造器將調用父類的預設構造器。父類構造器先於子類構造器執行,如果子類構造器有初始化執行器列表,它將先於父類構造器執行,如下是執行順序:

initializer list
superclass’s no-arg constructor
main class’s no-arg constructor

如果父類沒有預設構造器,你必須手動調用父類的其它構造器。寫法是在子類構造器名後面加上冒號(:),寫上父類構造器調用。
Because the arguments to the superclass constructor are evaluated before invoking the constructor, an argument can be an expression such as a function call:

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

註意:父類構造器的參數不接收this, 只能接受靜態方法。

Initializer list 初始化執行器

在構造器後面除了可以追加父類構造器外,還可以追加初始化執行器。

// Initializer list sets instance variables before
// the constructor body runs.
Point.fromJson(Map<String, num> json)
    : x = json['x'],
      y = json['y'] {
  print('In Point.fromJson(): ($x, $y)');
}

註意:右邊的初始化執行器不接受this寫法。

在開發模式下,你可以通過assert在初始化執行器中判斷參數是否為空。

Point.withAssert(this.x, this.y) : assert(x >= 0) {
  print('In Point.withAssert(): ($x, $y)');
}

Redirecting constructors 重定向構造器

有些時候,定義的構造器只為了傳遞給另一個構造器,那麼構造器的代碼體是空的,同時後面直接追加:目標構在器

class Point {
  num x, y;

  // The main constructor for this class.
  Point(this.x, this.y);

  // Delegates to the main constructor.
  Point.alongXAxis(num x) : this(x, 0);
}

Constant constructors 常量構造器

如果對象在創建後,不再改變,你可以將它寫成編譯常量。這些樣類,首先構造器要有const關鍵字,同時成員變數得是final.

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

  final num x, y;

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

Factory constructors 工廠構造器

當構造器使用factory關鍵字時,對象創建不一定每次都是一個新對象。factory可能從緩存中提取對象返回或者創建新對象。

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

  // _cache is library-private, thanks to
  // the _ in front of its name.
  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);
  }
}

註意:工廠對象不能使用this關鍵字

調用工廠構造器和其它構造器的寫法沒差別。

var logger = Logger('UI');
logger.log('Button clicked');

Methods 方法

Instance methods 成員方法

成員方法可以使用成員變數和this關鍵字,

import 'dart:math';

class Point {
  num x, 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);
  }
}

Getters and setters get和set

get和set是讀寫對象成語變數的特殊方法。通過.調用成員變數,就是調用內置的get方法,set方法也是一樣的。

你也可以通過get或者set關鍵字重載get和set方法

class Rectangle {
  num left, top, width, 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;
}

void main() {
  var rect = Rectangle(3, 4, 20, 15);
  assert(rect.left == 3);
  rect.right = 12;
  assert(rect.left == -8);
}

Note: Operators such as increment (++) work in the expected way, whether or not a getter is explicitly defined. To avoid any unexpected side effects, the operator calls the getter exactly once, saving its value in a temporary variable.

Abstract methods 抽象方法

成員方法,get方法,set方法都是定義為在抽象類中定義成抽象方法,註意是在抽象類中,非抽象類不可定義。

抽象方法直接在方法後加上;號,不用實現代碼。

abstract class Doer {
  // Define instance variables and methods...

  void doSomething(); // Define an abstract method.
}

class EffectiveDoer extends Doer {
  void doSomething() {
    // Provide an implementation, so the method is not abstract here...
  }
}

Abstract classes 抽象類

你可以用abstract關鍵字來定義抽象類,註意,抽象類不可初始化。抽象類適合做介面定義,具體實現通過繼承抽象類。抽象類的實現初始化方法,一般用工廠構造器。

// This class is declared abstract and thus
// can't be instantiated.
abstract class AbstractContainer {
  // Define constructors, fields, methods...

  void updateChildren(); // Abstract method.
}

Implicit interfaces 介面實現

如果A繼承B,則A將具備B的所有成員變數和方法,也同時具備B繼承的所有介面方法。但是,你如果不像繼承B類,但有希望擁有B類的方法,可以繼承B的相應介面。

// 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.';
}

// An implementation of the Person interface.
class Impostor implements Person {
  get _name => '';

  String greet(String who) => 'Hi $who. Do you know who I am?';
}

String greetBob(Person person) => person.greet('Bob');

void main() {
  print(greetBob(Person('Kathy')));
  print(greetBob(Impostor()));
}

下麵是多介面繼承例子,

class Point implements Comparable, Location {...}

Extending a class 擴展類

通過extends繼承父類,可以用super去訪問父類。

class Television {
  void turnOn() {
    _illuminateDisplay();
    _activateIrSensor();
  }
  // ···
}

class SmartTelevision extends Television {
  void turnOn() {
    super.turnOn();
    _bootNetworkInterface();
    _initializeMemory();
    _upgradeApps();
  }
  // ···
}

Overriding members 重載

子類可以重載成員方法,get方法,set 方法,你可以用@override是標記該方法被重載

class SmartTelevision extends Television {
  @override
  void turnOn() {...}
  // ···
}

To narrow the type of a method parameter or instance variable in code that is type safe, you can use the covariant keyword.

Overridable operators 操作符重載

你可以重載如下操作符:

< + | []

/ ^ []=
<= ~/ & ~
= * << ==
– % >>
‘註意:你會註意到!=是不用於重載的,因為它和==是等效的,比如(e1!=e2)和!(e1==e2)這兩個是相同效果'

下麵是+,-的重載示例:

class Vector {
  final int x, y;

  Vector(this.x, this.y);

  Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
  Vector operator -(Vector v) => Vector(x - v.x, y - v.y);

  // Operator == and hashCode not shown. For details, see note below.
  // ···
}

void main() {
  final v = Vector(2, 3);
  final w = Vector(2, 2);

  assert(v + w == Vector(4, 5));
  assert(v - w == Vector(0, 1));
}

註意:如果你重載了==,也需要重載hashCode方法。

noSuchMethod()

如果對象嘗試調用不存在的變數或者方法,會拋出noSuchMethod異常,這個異常可以通過重載該方法,增加自定義邏輯。

class A {
  // Unless you override noSuchMethod, using a
  // non-existent member results in a NoSuchMethodError.
  @override
  void noSuchMethod(Invocation invocation) {
    print('You tried to use a non-existent member: ' +
        '${invocation.memberName}');
  }
}

你一般不能調用未繼承的方法除非出現如下情況:

它是一個dynamic對象,因為是動態類型,所以編譯器不會檢查。

它繼承了一個抽象類,同時它沒有做抽象方法做具體實現,但是定義了 noSuchMethod()函數,這樣,編譯器也不會檢查。

更多的內容請查看noSuchMethod

Enumerated types 枚舉類型

枚舉類型一般用於表示一些限定範圍內的常量。

Using enums

可以用enum關鍵字定義枚舉。

enum Color { red, green, blue }

每個枚舉對象的屬性都會賦予一個整數值,它是從0開始,基於屬性位置遞增。例如,Color的枚舉對象,第一個是0,第二個是1

assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);

你可以使用values獲取枚舉屬性的值數組。

List<Color> colors = Color.values;
assert(colors[2] == Color.blue);

你可以用枚舉來做switch語句,編譯器會在你沒有處理所有枚舉屬性時,作出提示。

var aColor = Color.blue;

switch (aColor) {
  case Color.red:
    print('Red as roses!');
    break;
  case Color.green:
    print('Green as grass!');
    break;
  default: // Without this, you see a WARNING.
    print(aColor); // 'Color.blue'
}

枚舉類型有下麵的限制:
枚舉不可繼承,混入,也不可以被繼承
枚舉類不可初始化

Adding features to a class: mixins 混入

Mixins是一種在多個類中重用代碼的方式。

混入的寫法是:with關鍵字加上多個混入的類

class Musician extends Performer with Musical {
  // ···
}

class Maestro extends Person
    with Musical, Aggressive, Demented {
  Maestro(String maestroName) {
    name = maestroName;
    canConduct = true;
  }
}

用於mixin的對象是一個繼承Object的無構造函數的類,如果你想將用於混入的類和普通類區分開來,可以用 mixin關鍵字替代class.

mixin Musical {
  bool canPlayPiano = false;
  bool canCompose = false;
  bool canConduct = false;

  void entertainMe() {
    if (canPlayPiano) {
      print('Playing piano');
    } else if (canConduct) {
      print('Waving hands');
    } else {
      print('Humming to self');
    }
  }
}

mixin可以通過on關鍵字來限定哪些類的子類才可以用它做用戶(不太理解:To specify that only certain types can use the mixin — for example, so your mixin can invoke a method that it doesn’t define — use on to specify the required superclass:)

mixin MusicalPerformer on Musician {
  // ···
}

註意:mixin關鍵字在dart2.1採用到,早期版本用abstract class.

Class variables and methods 類成員變數和方法

使用static 關鍵字修飾類的成員變數和方法就形成了靜態變數和靜態方法。

Static variables 靜態變數

Static variables (class variables) are useful for class-wide state and constants:

class Queue {
  static const initialCapacity = 16;
  // ···
}

void main() {
  assert(Queue.initialCapacity == 16);
}

靜態變數在它使用時才初始化。

Static methods 靜態方法

靜態方法可以通過類直接調用:

import 'dart:math';

class Point {
  num x, y;
  Point(this.x, this.y);

  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 main() {
  var a = Point(2, 2);
  var b = Point(4, 4);
  var distance = Point.distanceBetween(a, b);
  assert(2.8 < distance && distance < 2.9);
  print(distance);
}

第八篇翻譯 ,Generics 泛型


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • FaaS介紹 微服務(MicroService)是以專註於單一服務/功能的小型單元塊為基礎,利用模塊化的方式組合成複雜的大型應用服務。 FaaS是Function as a Service的縮寫,可以簡單理解為功能服務化。FaaS提供了一種比微服務更加服務碎片化的軟體架構範式。FaaS可以讓研發只需 ...
  • 閑話少說,直接列舉問題: ①AB兩台資料庫伺服器做集群,由於兩台伺服器配置不一樣,如何在代碼中要實現每訪問伺服器A的資料庫2次,才能訪問伺服器B的資料庫1次。 ②AB兩台資料庫伺服器做讀寫分離,如何在代碼中控制,查詢數據使用伺服器A的資料庫連接,增刪改使用伺服器B的資料庫連接。 代碼結構: 代碼實現 ...
  • 一、概念 組合模式:允許你將對象組合成樹形結構來表現“整體/部分”層次結構。組合能讓客戶以一致的方式處理個別對象以及對象組合。 組合包含組件。組件有兩種:組合和葉節點元素。組合持有一群孩子,這些孩子可以是別的組合或者葉節點元素。 角色:  組合部件(Component):它是一個抽象角色, ...
  • WHAT 項目中必須對應的隱性需求-安全漏洞修複 WHY 小時候下圍棋,總樂於持白子。因為我的打法是“從那裡來我哪裡堵”,在防守中尋找對方的漏洞。這種作戰方法是有底層的思想根因的:就是懶惰。不願意去主動思考佈局。 在這一思想的引導下,我目前正面臨著過去十多年積累起來的困境。記得大學之前,面對一個認識 ...
  • 如果這是第二次看到我的文章,歡迎右側掃碼訂閱我喲~ 👉 本文長度為4229字,建議閱讀11分鐘。 這是本系列中既「數據一致性」後的第二章節——「高可用」的完結篇。 前面幾篇中z哥跟你聊了聊做「高可用」的意義,以及如何做「負載均衡」和「高可用三劍客」(熔斷、限流、降級,文末會附上前文連接:))。這次 ...
  • 工廠方法模式(Factory Method Pattern)定義了一個創建對象的介面,但由子類決定要實例化的類是哪一個。工廠方法讓類吧實例化推遲到子類。 ...
  • 題意 "題目鏈接" Sol 二維數點板子題 首先把詢問拆成四個矩形 然後離散化+樹狀數組統計就可以了 cpp include define int long long define LL long long using namespace std; const int MAXN = 1e6 + 10 ...
  • Python 可以通過 threading module 來創建新的線程,然而在創建線程的父線程關閉之後,相應的子線程可能卻沒有關閉,這可能是因為代碼中沒有使用 函數。接下來,使用一個例子來說明: ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...