# [Class](https://dart.dev/language/classes) * [Constructors](https://hackmd.io/@asdf121472/BJYsz1XG1g) * [Method](https://hackmd.io/@asdf121472/B14ZHRoMkx) * [extends 繼承](https://hackmd.io/@asdf121472/SJzdoOLXye) * [Mixin](https://hackmd.io/@asdf121472/r1y4xx_7Jl) * [implements](https://hackmd.io/@asdf121472/B16aZfDEJe) * [Extension methods](https://hackmd.io/@asdf121472/Hk8fumlEyx) * [Extension types](https://hackmd.io/@asdf121472/HJdwp-Q4kg) * [Enums](https://hackmd.io/@asdf121472/HySzeKlG0) * [Callable objects](https://hackmd.io/@asdf121472/HJ5BN2PV1g) * [Class modifiers](https://hackmd.io/@asdf121472/rJnfLO9Xyx) --- 參考資料: [1](https://ithelp.ithome.com.tw/m/articles/10265921) --- ### dart是單一繼承, 配合以下方式使class可再利用: * mixin * extension methods * extension type * implements * extends ### 類別成員 instance member: * 物件變數 * 物件方法 * **實作的介面** class member: * static variable * static method 使用點 ( . ) 來引用實例或類別的變數或方法 ### 使用建構函數初始化物件 Constructor names can be either ClassName or ClassName.identifier. ``` var p1 = Point(2, 2); var p2 = Point.fromJson({'x': 1, 'y': 2}); ``` 若要使用常數建構函式建立編譯時常數,請將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! ``` ### 取得物件的類型 ``` print('The type of a is ${a.runtimeType}'); assert(a is int); // 推薦 ``` ### Instance variables ``` class Point { double? x; // 可空變數初始值是null double y; double z = 0; // 不可空變數必須設定初始值(或用constructor來初始) Point(this.y); } ``` 實例變數都會產生隱式getter方法。非final or late final變數會產生隱式setter方法. 非late實例變數在物件初始化(建構函式)之前就要賦值, 此時this是不存在的. ``` double initialX = 1.5; class Point { // OK, 可以用全域變數來賦值 double? x = initialX; // ERROR, 此時實例還不存在 double? y = this.x; // OK, 只有在使用z時才會檢查, 那時實例已經建立 late double? z = this.x; // OK, `this.x` and `this.y` are parameter declarations, not expressions: Point(this.x, this.y); } ``` ### class本身就是接口 把一個class當接口時, 要實作其所有實例成員(實例的變數和方法, 簽名必須一樣) ``` class Person { String _name; Person(this._name); void intro() => print('Person name: $_name'); } class Student implements Person { String _name; String _id; Student(this._name, this._id); void intro() => print('Student name: $_name, ID: $_id'); } class CollegeStudent implements Student { String _name; String _id; int _age; CollegeStudent(this._name, this._id, this._age); void intro() => print('College student name: $_name, ID: $_id, age: $_age'); } void main() { var bob = CollegeStudent("Bob Smith", '123456', 19); bob.intro(); } ``` ``` // class B實作接口class A // 則B是A的subclass class A { int a; A(int b) : a = b; } class B implements A { int a; int b; B(this.a, this.b); } void main() { var aa = A(23); print(aa.a); var bb = B(12, 45); print(bb.b); assert(bb is A); assert (bb is B); // assert(aa is B); } ``` 可以實作多個接口 `class Point implements Comparable, Location {...}` ### 類別(靜態)變數和方法 使用`static`宣告變數或方法為類別所有, 用類別調用, 不是用實例調用. 靜態方法可以讀取靜態變數 ``` class Circle { static const pi = 3.14159; int originX, originY; Circle(this.originX, this.originY); // 不能讀取originX, originY, 但可直接讀取類別變數pi static num area(num radius) => pi * radius * radius; } void main() { num area = Circle.area(12); print(area); // 452.38895999999994 } ```