新公司迭代需求有點(diǎn)猛,拖了很長(zhǎng)時(shí)間。
計(jì)劃Dart還有一篇高級(jí)特性的筆記
[TOC]
類(lèi)的使用
通過(guò)構(gòu)造函數(shù)實(shí)例化
// 非 命名構(gòu)造函數(shù)
var test = Test();
// 命名構(gòu)造函數(shù)(named ctor)
var testFeature = TestFeature.fromTest(test);
// 常量構(gòu)造函數(shù)
var constObj1 = const TestConstCtor(1);
常量構(gòu)造函數(shù)
- const構(gòu)造函數(shù)必須用于成員變量都是final的類(lèi)
- 構(gòu)建常量實(shí)例必須使用定義的常量構(gòu)造函數(shù)枷餐,如果不是常量構(gòu)造函數(shù)是無(wú)法在實(shí)例化時(shí)使用const修飾符
- 如果實(shí)例化時(shí)不加const修飾符,即使調(diào)用的是聲明為const的構(gòu)造函數(shù),實(shí)例化的也不是常量實(shí)例
class TestConstCtor {
final int x;
// const構(gòu)造函數(shù)必須用于成員變量都是final的類(lèi)
// Can't define a constructor for a class with non-final fields
// String y;
const TestConstCtor(this.x);
}
void testConstCtor() {
// 構(gòu)建常量實(shí)例必須使用定義的常量構(gòu)造函數(shù)且轨,如果不是常量構(gòu)造函數(shù)是無(wú)法在實(shí)例化時(shí)使用const修飾符
// The constructor being called isn't a const constructor
// var test2 = const Test();
var constObj1 = const TestConstCtor(1);
var constObj2 = const TestConstCtor(2);
var constObj2_2 = const TestConstCtor(2);
// 如果實(shí)例化時(shí)不加const修飾符,即使調(diào)用的是聲明為const的構(gòu)造函數(shù)虚婿,實(shí)例化的也不是常量實(shí)例
var constObj2_3 = TestConstCtor(2);
print("const TestConstCtor(1) and const TestConstCtor(2) same: ${identical
(constObj1, constObj2)}"); //false
print("const TestConstCtor(2) and const TestConstCtor(2) same: ${identical
(constObj2_2, constObj2)}");//true
print("TestConstCtor(2) and const TestConstCtor(2) same: ${identical
(constObj2_2,constObj2_3)}");//false
}
對(duì)象的運(yùn)行時(shí)類(lèi)型
obj.runtimeType
返回的是對(duì)象的實(shí)際類(lèi)型旋奢,即使根據(jù)多態(tài)的特性將變量聲明為父類(lèi)類(lèi)型,runtimeType也會(huì)返回實(shí)際類(lèi)型
setter/getter
類(lèi)的成員變量默認(rèn)生成與字段同名的set/get函數(shù)
-
字面意義上的私有成員變量也會(huì)生成set/get函數(shù)然痊,在類(lèi)的外部可以調(diào)用
class TestFeature { int c; int d; int _f; // ... } test(){ var testFeature = TestFeature.fromTest(test); testFeature._f = 20; print("_f = ${testFeature._f}"); }
?
-
計(jì)算屬性的set/get
<type> get <computedProperty> { } set <computedProperty>(<type> value) { }
構(gòu)造函數(shù)
警告:初始化器的右邊部分中無(wú)法訪問(wèn)this關(guān)鍵字至朗。
默認(rèn)構(gòu)造函數(shù)
- 不聲明構(gòu)造函數(shù)則提供默認(rèn)構(gòu)造函數(shù)
- 只要有構(gòu)造函數(shù),即使是命名構(gòu)造函數(shù)剧浸,就不會(huì)提供默認(rèn)的構(gòu)造函數(shù)
- 無(wú)參數(shù)锹引,非命名
void testDef() {
// 只要有構(gòu)造函數(shù),即使是命名構(gòu)造函數(shù)唆香,就不會(huì)提供默認(rèn)的構(gòu)造函數(shù)
// The class 'TestDefault' doesn't have a default constructor
// var testDefault = TestDefault();
}
class TestDefault {
int a;
int b;
// TestDefault();
TestDefault.namedCtor(int c) {
a = c;
b = c;
}
}
帶參數(shù)的非命名構(gòu)造函數(shù)
-
直接給類(lèi)成員變量賦值的語(yǔ)法糖
class Test { int a; Test(this.a); }
-
構(gòu)造函數(shù)的參數(shù)列表與普通函數(shù)相同嫌变,可以處理無(wú)參,必須參數(shù)和可選參數(shù)等不同的情況
class TestNotNamed { int c; int d; int e; int f; // TestNotNamed(); // TestNotNamed(this.d); // TestNotNamed(this.c, {this.d, this.e, this.f}); // TestNotNamed(this.c, [this.d, this.e, this.f]); TestNotNamed(int x, int y) { c = x + y; } }
命名的構(gòu)造函數(shù)
使用命名構(gòu)造函數(shù)可以在一個(gè)類(lèi)中定義多個(gè)構(gòu)造函數(shù)躬它,不同的命名構(gòu)造函數(shù)可以專(zhuān)門(mén)用于不同的場(chǎng)景:
class Point {
num x, y;
Point(this.x, this.y);
// Named constructor
Point.origin() {
x = 0;
y = 0;
}
}
構(gòu)造函數(shù)沒(méi)有繼承
- 子類(lèi)不從父類(lèi)繼承構(gòu)造函數(shù)腾啥。
- 如果父類(lèi)有默認(rèn)構(gòu)造函數(shù),則子類(lèi)任意定義構(gòu)造函數(shù),默認(rèn)會(huì)調(diào)用執(zhí)行父類(lèi)的默認(rèn)構(gòu)造函數(shù)碑宴,不必強(qiáng)制使用初始化器列表調(diào)用父類(lèi)的構(gòu)造函數(shù)
- 父類(lèi)沒(méi)有提供默認(rèn)構(gòu)造函數(shù)软啼,子類(lèi)須要顯示指定使用父類(lèi)的哪一個(gè)構(gòu)造函數(shù),并傳遞參數(shù)
class TestParent {
int m;
TestParent.noArg();
}
class TestChild extends TestParent {
int x;
// 不顯示定義構(gòu)造函數(shù)則報(bào)錯(cuò)
// TestChild() :super.noArg();
TestChild.noArg() : super.noArg();
}
構(gòu)造函數(shù)的初始化器
初始化器在構(gòu)造函數(shù)聲明和方法體中間延柠。
構(gòu)造函數(shù)向初始化器傳遞參數(shù)
不需要使用this區(qū)分入?yún)⒑皖?lèi)的成員變量
Square(int id, int width, int height)
: super(id, width: width, height: height);
Square.bySize(int id, int size) : super(id, width: size, height: size);
super調(diào)用父類(lèi)構(gòu)造函數(shù)
- 父類(lèi)構(gòu)造函數(shù)初始化器必須是初始化器列表的最后一項(xiàng)
Square(int id, int width, int height)
: super(id, width: width, height: height);
Square.testInitList(int id)
: desc = "it's a desc",
// 重定向構(gòu)造函數(shù)初始化器必須單獨(dú)使用祸挪,不能和域初始化器和父類(lèi)構(gòu)造函數(shù)初始化器同時(shí)使用
// The redirecting constructor can't have a field initializer
// this.bySize(id,10),
super(id)
// 父類(lèi)構(gòu)造函數(shù)初始化器必須是初始化器列表的最后一項(xiàng)
// super call must be last in initializer list
// ,comment = "a new comment"
;
this重定向構(gòu)造函數(shù)
- 重定向構(gòu)造函數(shù)初始化器必須單獨(dú)使用,不能和域初始化器和父類(lèi)構(gòu)造函數(shù)初始化器同時(shí)使用
Rectangle.twiceWidth(int id, int width)
// 構(gòu)造函數(shù)重定向
// 初始化器不能使用this贞间,也就是只能使用頂層函數(shù)和static靜態(tài)函數(shù)
: this(id, width: width, height: getTwiceWidth(width));
Square.testInitList(int id)
: desc = "it's a desc",
// 重定向構(gòu)造函數(shù)初始化器必須單獨(dú)使用贿条,不能和域初始化器和父類(lèi)構(gòu)造函數(shù)初始化器同時(shí)使用
// The redirecting constructor can't have a field initializer
// this.bySize(id,10)
初始化實(shí)例變量
class Square extends Rectangle {
String comment;
// ...
Square.initMember()
:comment="a comment",
super(1);
}
工廠構(gòu)造函數(shù)
- 構(gòu)造函數(shù)前使用
factory
關(guān)鍵字標(biāo)識(shí)其是工廠構(gòu)造函數(shù) - factory 聲明的工廠構(gòu)造函數(shù)不能使用this關(guān)鍵字,這種構(gòu)造函數(shù)類(lèi)似static靜態(tài)函數(shù)
class TestFactory {
final String factoryName;
static final Map<String, TestFactory> _cache = <String, TestFactory>{};
TestFactory._internal(this.factoryName);
// factory 聲明的工廠構(gòu)造函數(shù)不能使用this關(guān)鍵字增热,這種構(gòu)造函數(shù)類(lèi)似static靜態(tài)函數(shù)
// Initializing formal parameters can't be used in factory constructors.
// factory TestFactory(this.factoryName);
factory TestFactory(String factoryName) {
var instance = _cache[factoryName];
if (null == instance) {
instance = TestFactory._internal(factoryName);
_cache[factoryName] = instance;
return instance;
} else {
return instance;
}
}
}
類(lèi)的特性
類(lèi)的實(shí)例方法/set/get/計(jì)算屬性
set/get默認(rèn)實(shí)現(xiàn)整以,不需要顯式聲明和實(shí)現(xiàn)
-
如果需要處理set/get,按照特定格式聲明set/get
<type> get <property> { } // 顯式定義setter時(shí)避免設(shè)置返回類(lèi)型 // avoid return type on setters /*void*/ set <property>(<params>) { }
-
可以通過(guò)set/get設(shè)置計(jì)算屬性峻仇。但是與Vue不同公黑,調(diào)用計(jì)算屬性的get仍然每次都會(huì)執(zhí)行計(jì)算
class TestMethod { int a; int b; int c; int d; TestMethod(this.a, this.b, this.c, this.d); int get e { // 計(jì)算屬性在執(zhí)行g(shù)etter方法時(shí)每次都會(huì)執(zhí)行statement,與Vue的計(jì)算屬性不同 print("get e"); int ret = a + b; return ret; } // 顯式定義setter時(shí)避免設(shè)置返回類(lèi)型 // avoid return type on setters /*void*/ set e(int vi) { a = vi - b; } }
?
抽象類(lèi)與抽象方法摄咆、隱式接口
- 抽象類(lèi)不能(用new)實(shí)例化
- 每個(gè)類(lèi)都提供一個(gè)同名的凡蚜,包含所有方法的隱式接口
- 接口類(lèi)的聲明使用
abstract class XXX
- set/get 也可以聲明為abstract交由子類(lèi)具體實(shí)現(xiàn)
abstract class TestAbstract {
void methodA() => print("real method");
void abstractMethod(String text);
int a;
int get abstractGet;
set abstractSet(int value);
}
class TestAbstractImpl extends TestAbstract {
@override
// TODO: implement abstractGet
int get abstractGet => null;
@override
void abstractMethod(String text) {
// TODO: implement abstractMethod
}
@override
void set abstractSet(int value) {
// TODO: implement abstractSet
}
// noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class TestInterface {
void saySth(String text) {
print(text);
}
}
class TestInterfaceImpl implements TestInterface {
@override
void saySth(String text) {
// TODO: implement saySth
}
}
操作符override
- 函數(shù)名為操作符,函數(shù)名前使用
operator
標(biāo)識(shí)<returnType> operator <op>(<params>) {}
- 支持的操作符
< | + | | | [] |
> | / | ^ | []= |
<= | ~/ | & | ~ |
>= | * | << | == |
- | % | >> |
class TestOverrideOperator {
int a;
int b;
TestOverrideOperator(this.a, this.b);
TestOverrideOperator operator +(TestOverrideOperator opVal) =>
TestOverrideOperator(this.a + opVal.a, this.b + opVal.b);
@override
String toString() {
return 'TestOverrideOperator{a: $a, b: $b}';
}
}
noSuchMethod
重寫(xiě)noSuchMethod()方法來(lái)處理程序訪問(wèn)一個(gè)不存在的方法或者成員變量
class Foo {
void sayHi() => print("hi");
int get money => 123;
}
class TestNoSuchMethod implements Foo {
void hello() => print("hello");
int get salary => 777;
@override
noSuchMethod(Invocation invocation) {
var runtimeType = invocation.runtimeType;
// invocation.memberName 返回的是Symbol對(duì)象吭从,
// #操作符 用于引用一個(gè)操作符(方法名)
if (invocation.memberName == #sayHi) {
if (invocation.isMethod) {
return hello();
}
} else if (invocation.memberName == #money) {
if (invocation.isGetter) {
// 如果調(diào)用的是get/set方法朝蜘,應(yīng)當(dāng)返回一個(gè)get/set方法的返回值
// return hello;
return salary;
}
}
return super.noSuchMethod(invocation);
}
}
mixin多繼承
- 子類(lèi)使用
with
標(biāo)識(shí)符聲明其他繼承 - Mixin類(lèi)必須是Object的直接子類(lèi)
- Mixin類(lèi)不能聲明構(gòu)造函數(shù)
- Mixin類(lèi)中不能出現(xiàn)super語(yǔ)句
class TestMixin extends Parent with MixinA {
String b;
}
class Parent {
int a;
}
class MixinA {
int c;
// MixinA(this.c);
void play(String text) {
print(text);
// super.toString();
}
}
枚舉
- 枚舉的values下標(biāo)從0開(kāi)始
-
<type>.values
返回所有的枚舉值 - enum 使用switch必須把所有枚舉都列出,否則報(bào)錯(cuò)
void testEnum() {
// 獲取所有的枚舉值
var values = TestEum.values;
// 枚舉的values下標(biāo)從0開(kāi)始
var index2 = TestEum.TypeTwo.index;
print("values:${values};index2:${index2}");
var type = TestEum.TypeThree;
// enum 使用switch必須把所有枚舉都列出涩金,否則報(bào)錯(cuò)
switch (type) {
case TestEum.TypeOne:
break;
case TestEum.TypeTwo:
break;
case TestEum.TypeThree:
break;
}
}
enum TestEum { TypeOne, TypeTwo, TypeThree }
泛型
- 與java寫(xiě)法類(lèi)似谱醇,可以在類(lèi)上和方法上使用泛型
- 運(yùn)行時(shí)不會(huì)泛型擦除
- 泛型標(biāo)記不能實(shí)例化
void testGenericClass() {
TestGeneric<MyImplA>(MyImplA(3, 5)).printDataName();
TestGeneric<MyImplB>(MyImplB(41, 8)).printDataName();
}
class TestGeneric<T extends MyInterface> {
final T data;
TestGeneric(this.data);
void printDataName() {
print("for ${T}:name=${data.getName()}");
}
// 泛型S不能實(shí)例化
// S newInstance<S extends String>(String message) {
// return new S(message);
// }
}
abstract class MyInterface {
String getName();
}
class MyImplA implements MyInterface {
int a;
int b;
MyImplA(this.a, this.b);
@override
String getName() {
return (a + b).toString();
}
}
class MyImplB implements MyInterface {
int c;
int d;
MyImplB(this.c, this.d);
@override
String getName() {
return (c * d).toString();
}
}