06.Dart - 類

個人學習用
不嚴謹
學習的話請看別的博客

使用類的成員

void main() {
  /**
   * Dart 是支持基於 mixin 繼承機制的面嚮對象語言,所有對象都是一個類的實例,而所有的類都繼承自 Object 類。基於 mixin 的繼承 意味着每個除 Object 類之外的類都只有一個超類,
   * Extension 方法是一種在不更改類或創建子類的情況下向類添加功能的方式。
   *
   * 使用(.)來訪問對象的實例變量或方法
   * 使用?.代替 . 可以避免左邊的表達式爲null而導致的問題
   *
   */
  print(MyClazz.a); //調用靜態變量
  MyClazz clazz = new MyClazz();

  clazz.b;
  clazz.showText();
}

class MyClazz {
  static int a = 1;
  int b = 2;

  void showText() {
    print('$a$b');
  }
}

使用構造函數

void main() {
  /**
   * 使用構造函數
   * 命名方式:
   *    類名  或者  類名.標識符 的形式
   *
   *
   */
  var p1 = Paint(1, 2);
  var p2 = Paint.fromJson({"x": 1, "y": 2});
  var p3 = Paint.fromJson({"a": 1, "b": 2});

  p1.showText(); // 1 2
  p2.showText(); // 1 2
  p3.showText(); //null  null ,因爲傳值時候 鍵值對不正確,鍵名字錯誤,方法鍵是 xy ,我使用的是 ab
}

class Paint {
  int x;
  int y;

  Paint(this.x, this.y);

  Paint.fromJson(Map<String, int> jsonMap) {
    this.x = jsonMap["x"];
    this.y = jsonMap["y"];
  }

  void showText(){
    print(x);
    print(y);
  }
}

常量構造函數

void main() {
  /**
   *常量構造函數
   * 使用常量構造函數創建對象時,參數一樣情況下,創建的對象是一個
   *
   */

  //使用時候要用 const來定義 構造函數

  var p1 = const Porint(1, 2);
  var p2 = const Porint(1, 2);
  var p3 = Porint(1, 2);
  print(p1 == p2); //true
  print(p1 == p3); //false
  print(p2 == p3); //false
}

// 常量構造函數:final定義屬性,const定義構造方法
class Porint {
  final int a; //final定義屬性
  final int b;

  const Porint(this.a, this.b); //const定義構造方法

  void showText() {
    print('$a$b');
  }
}

獲取對象的類型

void main() {
  /**
   * 獲取對象類型
   * 使用 對象名.runtimeType來獲取運行時對象的類型
   *
   */

  var p1 = Point(1, 2);
  var p2 = Point.fromJson({'x': 3, 'y': 4});
  var p3;
  print(p1.runtimeType);//Point
  print(p2.runtimeType);//Point
  print(p3.runtimeType);//Null
}

class Point {
  int a;
  int b;

  Point(this.a, this.b);

  Point.fromJson(Map<String, int> jsonMap) {
    this.a = jsonMap['x'];
    this.b = jsonMap['y'];
  }

}

實例變量

void main() {
  /**
   * 實例變量
   * 所有實例變量均會隱式地聲明一個 Getter 方法,非 final 類型的實例變量還會隱式地聲明一個 Setter 方法。
   *
   */
}

class Potin {
  int x; //聲明實例變量 x 並初始化爲 null。
  int y; //聲明實例變量 y 並初始化爲 null。
  int z = 0; // 聲明實例變量 z 並初始化爲 0。
//所有實例變量均會隱式地聲明一個 Getter 方法,
// 非 final 類型的實例變量還會隱式地聲明一個 Setter 方法。
}

構造函數

void main() {
  /**
   * 構造函數
   */
}

class Point {
  int x;
  int y;

//  Point(this.x, this.y); //構造方法語法糖

  //默認構造函數
  Point(int x, int y) {
    this.x = x;
    this.y = y;
  }

  //命名構造函數
  Point.mingming(int i, int j) {
    this.x = i;
    this.y = j;
  }
}

方法

void main() {
  /**
   * 方法
   */
}

class Point {
  int x, y;

  Point(this.x, this.y);

  int getNum(Point other) {
    return this.x + this.y + other.x + other.y;
  }

  int get getTop => x + y; //get方法

  set setTop(int i) => i - x;//set方法
}

抽象方法

void main() {
  /**
   * 抽象方法
   * 實例方法.Getter方法以及Setter方法都可以是抽象方法
   * 定義一個接口方法而不去做具體的實現讓實現他的類去實現該方法
   * 抽象方法只能存在於抽象類中
   *
   */
}

//被abs修飾了,是抽象類
abstract class Father {
  void show(); //沒有{} 所以是抽象方法
}

class Son extends Father {
  /**
   * 重寫抽象類中的抽象方法
   */
  @override
  void show() {
    print("你好,我是被重寫的方法");
  }
}

抽象類

void main(){
  /**
   * 抽象類
   * 1.被abstract修飾的類 爲 抽象類,抽象類無法被實例化
   * 2.抽象類常用於聲明接口方法,有時也會有具體的實現方法
   * 3.如果想讓抽象類可被實例化,可以爲抽象類定義 工廠構造函數
   * 4.有抽象方法的類一定是抽象類,抽象類裏不一定有抽象方法
   *
   */
}

abstract class Point{
  void show();
}

隱式接口

void main() {
  /**
   * 每一個類都隱式的定義了一個接口並且實現了該接口
   * 這個接口包含: 所有這個類的實例成員  以及這個類所實現的其它接口
   * 如果創建類A支持調用B類的API,但是又不想竭誠B類,則可以實現B類的接口
   *
   * 如果想要實現多個接口,則可以再 class Point implements Comparable, Location {...}
   */
  String getHi(Person person) => person.getString("張三");
  print(getHi(Person("李四"))); //你好,張三,我是李四
  print(getHi(Son())); //你好張三
}

class Person {
  final _name;

  Person(this._name);

  String getString(who) => '你好,$who,我是$_name';
}

class Son implements Person {
  get _name => '我是默認的名字';

  @override
  String getString(String who) {
    return '你好$who';
  }
}

擴展一個類

void main() {
  /**
   * 使用 extend繼承來 擴展一個類
   *
   */

  var s = Son(3);
  s.show(); //章金來

  s.showMore(); //章金來  //我今年3歲了
}

class Father {
  String xing;
  String ming;

  Father(this.xing, this.ming);

  void show() {
    print('$xing$ming');
  }
}

class Son extends Father {
  int age;

  Son(this.age) : super('章', '金來');

  /**
   * 重寫的show方法
   */
  @override
  void show() {
    super.show();
  }

  void showMore() {
    super.show();
    print('我今年$age歲了');
  }

}

重寫操作符

void main() {
  /**
   * 重寫操作符: 通過operator方法可以重寫 原來的操作符,達到自定義的效果
   * 優先級: 混合運算時候 返回值要匹配,並且優先級不變
   */

  var c1 = CaoZuo(1, 2);
  var c2 = CaoZuo(3, 4);

  print((c1 + c2).x); //4
  print((c1 + c2).y); //-2
  print((c1 - c2).x); //4
  print((c1 - c2).y); //8

}

class CaoZuo {
  int x, y;

  CaoZuo(this.x, this.y);

  //重寫 + 操作符
  CaoZuo operator +(CaoZuo other) => CaoZuo(this.x + other.x, this.y - other.y);

  //重寫 - 操作符
  CaoZuo operator -(CaoZuo other) {
    CaoZuo caoZuo = new CaoZuo(this.x, this.y);
    caoZuo.x = caoZuo.x + other.x;
    caoZuo.y = caoZuo.y * other.y;
    return caoZuo;
  }
}

Extension擴展

void main() {
  /**
   * Extension 方法 ,擴展,增加的意思
   * 在Dart2.7中引入,爲現有的庫中添加功能的方法
   * 在 IDE 中使用代碼完成功能時,它建議將 Extension 方法與常規方法一起使用
   * 不能對 dynamic使用這樣的方法
   *
   *
   *衝突:
      如果擴展成員與接口或其他擴展成員發生衝突,則有幾個選項。
      1.更改導入衝突擴展的方式,使用show或hide公開或者隱藏API :
      import 'string_apis_2.dart' hide NumberParsing2;
      2.另一個選項是顯式地應用擴展
      NumberToString('111').parseInt()
      3.如果兩個擴展名相同,則可能需要使用前綴導入
      import 'string_apis.dart';
      import 'string_apis_3.dart' as rad;  // 使用了前綴  as  red ,前綴名是 red
      print(NumberParsing('42').parseInt());
      print(rad.NumberParsing('42').parseInt());  //前綴的調用方式

   */
  print('42'.parseInt());
  print(NumberToString('111').parseInt()); //顯示調用
  dynamic d = '123';
  var v = '123';

  //dynamic定義的數據 會報錯
  //dynamic定義的數據 會報錯
//  print(d.parseInt());//NoSuchMethodError: Class 'String' has no instance method 'parseInt'.
  print(v.parseInt()); // 不會報錯,因爲變量v被推斷爲類型String:
}

/**
 * 使用這個方式把parseInt方法,添加到String中
 */
extension NumberToString on String {
  int parseInt() {
    return int.parse(this);
  }

  double parseDouble() {
    return double.parse(this);
  }
  
}

枚舉類型

enum Color { red, green, blue }
//enum 不能再方法內部定義,會報錯
void main() {
  /**
   * 枚舉類型 Enumerated types
   * 也稱爲 enumerations 或 enums,用於定義一些固定數量的常量值
   * 每一個枚舉值都有一個名爲 index 成員變量的 Getter 方法
   */

  print(Color.red.index); //0
  print(Color.green.index); //1
  print(Color.blue.index); //2

  //使用枚舉的 values方法 獲取到 所有枚舉的 值的列表
  List<Color> list = Color.values;
  print(list);

  //可以用在switch語句中
  switch (Color.red) {
    case Color.red:
      break;

    case Color.green:
      break;

    case Color.blue:
      break;
  }

  //枚舉的限制:

  //不能成爲子類,
  //不能實現枚舉
  //不能顯式的實例化一個枚舉類
  //不能 mixin
}

Mixin模式

void main() {
  /**
   * Mixin 混合模式
   * 使用 with 關鍵字,可以實現多類似於多繼承
   */

  TestSon son = TestSon();
  son.show();
}

//只能 子類實現
class TestSon extends Test with Music {
  show();
}

class Test {}

//定義一個Mixin類,
//1.使用mixin關鍵字,不能使用class
//2.使用on 關鍵字,後面跟上 可以 mixin的類,只有繼承了Test類的子類纔可以使用 whth Music
mixin Music on Test {
  //3.不能定義構造方法
  int x, y, z;

  void show() {
    print('$x$y$z');
  }
}

靜態變量和靜態方法

void main() {
  /**
   * 靜態變量 和  靜態方法
   *
   * 靜態變量在首次使用的時候被初始化
   * 靜態方法不能使用實例來調用,因爲靜態加入內存比較早,實例比較晚
   * 靜態只能訪問靜態
   */
}

class Point {
  static int i = 1;

  static void show(){
    print(i);
  }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章