文内所使用的Dart版本为2.17.0
一、对比
extends
数量: 仅一个
对象: 任意类(class)
附注:
- 可覆写(建议使用
@override
注解)被继承对象所有的非静态(static)的属性
或方法
。 - 对于用
abstract
修饰的属性或方法,若继承者不为抽象类则必需覆写。 - 对于用
final
修饰的属性则为覆写其get
方法。
with
数量: 多个(至少一个)
对象: 没有构造方法
的任意类(class)或任意混入(mixin)
附注: (这里为表述简洁,使用了子类的说法代指了混入关系)
- 属性和方法的覆写规则同
extends
。 - 可以直接使用
mixin
关键字修饰with对象(一定程度上可以把mixin看作是特殊的abstract class),此时可使用on
关键字限定一个class或mixin
对象,只有该被限定对象的子类
可通过with使用该mixin修饰的对象(当on限定对象为mixin且其子类同时使用该被修饰对象时,在其子类的with子句中被限定对象要排在该被修饰对象之前)。 - 对于各被混入对象的同名属性或方法,
排列靠后的覆盖排列靠前的
。
implements
数量: 多个(至少一个)
对象: 任意类(class)或任意混入(mixin)
附注:
- 被实现对象的
所有非静态(static)属性和方法
均被视为是抽象的(abstract)
,无论是否使用了abstract修饰。 - 在上一条的前提下,属性和方法的覆写规则同
extends
。
附注
- 三者可以同时使用,顺序依次为
extends、with、implements
。 - extends和with同时使用时,对于同名属性和方法的覆盖顺序为:
类中的覆写 > with > extends
,对于super
的指代:with > extends
。对于implements
,因其特性所以不讨论覆盖顺序(因为它相当于没有值或方法体,可以认为始终处于覆盖顺序的最底层)。 - 仅
with
和implements
可以同时使用同一个对象,其效果等价于只有修饰了abstract
关键字的属性或方法是抽象的。
二、示例
extends
// 压缩排版,下同
void main() {
final b = B();
b.c(); // B-c
b.f(); // B-f
}
abstract class A {
var a = 0;
final b = 1;
void c() { print('A-c'); }
abstract int d;
abstract final int e;
void f();
}
class B extends A {
@override void c() { print('B-c'); }
@override int d = 0;
@override int get e => 1;
@override void f() { print('B-f'); }
}
with
基本使用:
void main() {
E().test(); // B
F().test(); // C
}
class A { A(); }
/*abstract */class B { void test() { print('B'); } }
mixin C { void test() { print('C'); } }
// class D with A {} // 错误:被混入对象不能有构造方法
class E with B {}
class F with C {}
排列靠后的覆盖排列靠前的:
void main() {
C1().test(); // B
C2().test(); // A
}
/*abstract */class A { void test() { print('A'); } }
mixin B { void test() { print('B'); } }
class C1 with A, B {}
class C2 with B, A {}
使用on限定:
void main() {
D1().test(); // B1
D2().test(); // B2
}
class A1 { void test() { print('A1'); } }
mixin B1 on A1 { void test() { print('B1'); } }
// class C1 with B1 {} // 错误:C1不是A1的子类
class D1 extends A1 with B1 {}
// ******
mixin A2 { void test() { print('A2'); } }
mixin B2 on A2 { void test() { print('B2'); } }
// class C2 with B2 {} // 错误:C2不是A2的子类
class D2 with A2, B2 {} // 不能是 “with B2, A2”,理由同上
implements
/*abstract */class A {
var a = 0;
void b() { print('A-b'); }
}
class B implements A { // 均被视为abstract
@override int a = 1;
@override void b() { print('B-b'); }
}
其它示例
覆盖顺序:
void main() {
D().test(); // B2
E().test(); // E
F().test(); // F
G().test(); // G
}
/*abstract */class A { void test() { print('A'); } }
/*abstract */class B1 { void test() { print('B1'); } }
/*abstract */class B2 { void test() { print('B2'); } }
/*abstract */class C1 { void test() { print('C1'); } }
/*abstract */class C2 { void test() { print('C2'); } }
// with > extends
class D extends A with B1, B2/* implements C1, C2*/ {}
// 类中覆写 > extends
class E extends A/* implements C1, C2*/ { @override void test() { print('E'); } }
// 类中覆写 > with
class F with B1, B2/* implements C1, C2*/ { @override void test() { print('F'); } }
// 类中覆写 > with > extends,对于implements因其特性不讨论
class G extends A with B1, B2/* implements C1, C2*/ { @override void test() { print('G'); } }