面向对象扩展
概要
继承,继承中的构造方法
抽象类
接口
Mixins,操作符的覆写
1.继承
- 使用关键字 extends 继承一个类
- 子类会继承父类可见的属性和方法,不会继承构造方法
- 子类能够复写父类的方法,getter 和 setter
- 单继承,多态性
// 父类
class Person {
String name;
int age;
String _birthday;
bool get isAdult => age > 18;
void run() {
print("Person run...");
}
// 这个方法是继承 Object 类,Dart语言中类未指定父类的,默认都是继承 Object类
@override
String toString() {
return "Name is $name,Age is $age";
}
}
// 继承于 Person 类的子类
class Student extends Person {
void study() {
print("Student study...");
}
// 复写父类的计算属性
@override
bool get isAdult => age > 15;
// 复写父类的 run() 方法
@override
void run() {
print("Student run...");
}
}
void main() {
var student = new Student();
student.study();
// 访问父类属性,但不能访问私有属性(如: _birthday属性)
student.name = "Tow";
student.age = 16;
print(student.isAdult);
// 访问父类方法
student.run();
// 多态
// person 接收一个 Student 类实例,可访问 Person 类的方法属性,不可访问 Sutdent 类方法属性。
Person person = new Student();
// 通过对象操作符,判断是否 Student 类,条件满足则 if 里可以访问 study() 方法
if (person is Student) {
person.study();
}
// 会执行 Person 类中的 toString() 方法
print(person);
}
- 继承中的构造方法
- 子类的构造方法默认会调用父类的无名无参构造方法
- 如果父类没有无名无参构造方法,则需要显示调用父类构造方法
- 在构造方法参数后使用 : 显示调用父类构造方法
// 父类
class Person {
String name;
// 无名无参构造方法,默认方法
// Person() {
// // 可加入一些 code
// print("Person...");
//}
// 自定义构造
Person(this.name);
Person.withName(this.name);
}
// 子类
class Student extends Person {
int age;
// 必须实现父类构造方法来实现子类构造方法
Student(String name) : super(name);
// 或者写成
Student(String name) : super.withName(name);
// 或者写成
Student.withAge(int age) : super(name);
}
void main() {
var student = new Student("Tom");
print(student.name);
}
- 构造方法执行顺序
- 父类的构造方法在子类构造方法体开始执行的位置调用
- 如果有初始化列表,初始化列表会在父类构造方法之前执行
// 父类
class Person {
String name;
// 无名无参构造方法,默认方法
// Person() {
// // 可加入一些 code
// print("Person...");
//}
// 自定义构造
Person(this.name);
Person.withName(this.name);
}
// 子类
class Student extends Person {
int age;
final String gender;
// 必须实现父类构造方法来实现子类构造方法
// 有初始化列表,初始化列表会在父类构造方法之前执行
Student(String name, String g) : gender = g, super(name);
// 错误书写
Student(String name, String g) : super(name), gender = g;
}
void main() {
var student = new Student("Tom", "Male");
print(student.name);
}
- 抽象类
- 抽象类使用
abstract
表示,不能直接被实例化 - 抽象方法不用
abstract
修饰,无实现 - 抽象类可以没有抽象方法
- 有抽象方法的类一定得声明为抽象类
abstract class Person {
// 无实现的抽象方法,子类必须实现方法
void run();
// 或者写成,子类可选实现方法
void run() {}
}
// 子类继承抽象类
class Student extends Person {
@override
void run() {
print("run...");
}
}
void main() {
var student = new Student();
student.run();
}
- 接口
- 类和接口是统一的,类就是接口
- 每个类都隐式的定义了一个包含所有实例成员的接口
- 如果是复用已有类的实现,使用继承
extends
- 如果只是使用已有类的外在行为,使用接口
implements
// 接口代码演示
class Person {
String name;
int get age => 18;
void run() {
print("Person run...");
}
}
class Student implements Person {
// 重写实现
@override
String name;
// 重写实现
@override
int get age => null;
// 重写实现
@override
void run() {
}
}
void main() {
var student = new Student();
student.run();
}
// 推荐抽象类方式,去对外接口定义
abstract class Person {
void run();
}
class Student implements Person {
@override
void run() {
print("Student run...");
}
}
void main() {
var student = new Student();
student.run();
}
- Mixins
-
Mixins
类似于多继承,是在多类继承中重用一个类代码的方式 - 作为
Mixins
的类不能有显示声明构造方法 - 作为
Mixins
的类只能继承自Object
- 使用关键字
with
连接一个或多个Mixin
// Mixins 例子
void main() {
var d = new D();
// 打印 ``with``连接的最后一个 ``Mixin`` 类中的``a()``方法
// 打印结果:"C.a()..."
d.a();
}
class A {
void a() {
print("A.a()...");
}
}
class B {
void a() {
print("B.a()...");
}
void b() {
print("B.b()...");
}
}
class C {
void a() {
print("C.a()...");
}
void b() {
print("C.b()...");
}
void c() {
print("C.c()...");
}
}
// B,C类是``Mixins``类,类中不能有显示声明构造方法,只能继承自``Object``
class D extends A with B,C {
}
// Mixins 例子
abstract class Engine {
void work();
}
class OilEngine implements Engine {
@override
void work() {
print("work with oil...");
}
}
class ElectricEngine implements Engine {
@override
void work() {
print("work with Electric...");
}
}
class Tyre {
String name;
void run() {}
}
// 使用``Mixins``时,正常书写方法
class Car extends Tyre with ElectricEngine {
String type;
}
// 使用``Mixins``时,可书写这种是简写方式,但``Car``、``Bus``类不能自定义属性方法
class Car = Tyre with ElectricEngine;
class Bus = Tyre with OilEngine;
- 操作符覆写
- 覆写操作符需要在类中定义
返回类型 operator 操作符 (参数1,参数2,...) {
实现体...
return 返回值
}
- 如果覆写
==
,还需要覆写对象的hashCode
getter
方法,可以通过编译器直接覆写,在编辑区右击选择Generate
,再选择==() and hashCode
, 弹出属性选择框如有多个属性可选择多个属性相等时,类才相等 - 操作符覆写要定义在类里
-
可覆写操作符,如图:可覆写的操作符.png
// 例子
void main() {
var person1 = new Person(10);
var person2 = new Person(20);
// 比较
print(preson1 > person2);
// 取值打印
print(person1.age);
print(person1['age']);
// 是否相等,``==`` 这操作符是通过编译器帮覆写了
print(person1 == person2);
}
class Person {
int age;
Person(this.age);
bool operator >(Person person) {
return this.age > person.age;
}
int operator [](String str) {
if ("age" == str) {
return age;
}
return 0;
}
}