文章目录
类是面向对象编程语言中最为重要的一类概念,Dart中的类也只支持一个父类,除了null
外,所有类的超类都为Object
一、类
1.class 定义一个类
class
关键字标识一个类的定义,在类内部可以定义其成员变量:
class P {
String? name;// 可空对象不初始化,值默认为null
int? age;
int gender = 0;
}
2.构造函数
Dart和Java一样,如果你没有定义构造函数,那么运行时会自动生成一个空的构造并调用父类的空构造,定义构造函数与类名相同,防止参数名与成员变量名重复,构造函数中可以通过this.成员变量名
进行赋值:
class P {
String? name; // 可空对象不初始化,值默认为null
int? age;
int gender = 0;
P(String name, int age, int gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
}
Dart中以类名为方法名的构造函数只能有一个,如果你想传递不同数量的参数,可以使用可选参数:
class P {
String? name; // 可空对象不初始化,值默认为null
int? age;
int gender = 0;
P({String? name, int? age, int? gender}) {
this.name = name;
this.age = age;
this.gender = gender ?? 0;
}
}
2.1 终值初始化
Dart提供了一种简便的构造函数语法糖:类名(this.成员变量1,this.成员变量2...);
,其中也是支持可选参数的语法,将上面的构造函数改写后:
class P {
String? name; // 可空对象不初始化,值默认为null
int? age;
int gender = 0;
// 对于非空成员变量,可选参数中赋值一个默认值
P({this.name, this.age, this.gender = 0});
// P({String? name, int? age, int? gender}) {
// this.name = name;
// this.age = age;
// this.gender = gender ?? 0;
// }
}
2.2 命名式构造函数
虽然只允许我们定义一个类名构造函数,但Dart提供了另外定义构造函数的方式,命名式构造函数:类名.方法名()
,这样方法名不同,就可以作进一步的区分
class P {
String? name; // 可空对象不初始化,值默认为null
int? age;
int gender = 0;
P({this.name, this.age, this.gender = 0});
// 定义命名式构造函数 name age必传 ,gender非必须
P.gen1(String name, int age, {int? gender}) {
this.name = name;
this.age = age;
this.gender = gender ?? 0;
}
}
main() {
P p = P.gen1("hi", 23);
}
命名式构造函数也支持终值语法糖:
class P {
String? name; // 可空对象不初始化,值默认为null
int? age;
int gender = 0;
...
P.gen2(this.name, this.age);
}
2.3 初始化列表
所有构造函数支持在后面跟上一个:
进行初始化成员变量,每个成员变量之间使用,
分隔,下面是将name和age在初始化列表中进行初始化的代码:
class P {
String? name; // 可空对象不初始化,值默认为null
int? age;
int gender = 0;
// name age必传 ,gender非必须
P.gen1(String name, int age, {int? gender})
: this.name = name,
this.age = age {
this.gender = gender ?? 0;
}
}
3.子类
3.1 extends 继承父类
子类通过extends
关键字指定父类,子类的构造函数默认继承父类的匿名无参数构造方法:
class Man extends P {
int? height;
}
3.2 子类构造
子类定义构造函数时可以通过:
+ super.父类构造函数
手动指定一个父类构造,该父类构造可以时常规构造函数,也可以时命名式构造函数,子类构造函数中的参数可以直接传递到父类构造中:
// 子类
class Man extends P {
int? height;
Man(String name, int age, int height) : super.gen2(name, age) {
this.height = height;
}
}
除了this
支持终值语法糖,super
也支持,我们将子类构造简化后:
// 子类
class Man extends P {
int? height;
Man(super.name, super.age, this.height) : super.gen2();
}
4.其他构造函数
上面我们使用了常用的构造函数,Dart中还有一些用的较少的
4.1 重定向构造函数
重定向构造函数和继承父构造函数类似,有时候类中的构造函数仅用于调用类中其它的构造函数,没有函数体,只需在该构造函数后使用:
指定需要重定向到的其它构造函数 (使用 this
而非类名)
class P {
String? name;
int? age;
int gender = 0;
P(this.name, this.age, this.gender);
P.base(String name) : this(name, null, 0);
}
4.2 常量构造函数
如果类生成的对象都是不变的,可以在生成这些对象时就将其变为编译时常量。你可以在类的构造函数前加上 const
关键字并确保所有实例变量均为 final
来实现该功能。
class P {
final String? name;
final int? age;
final int gender;
const P(this.name, this.age, this.gender);
}
4.3 工厂构造函数
使用factory
修饰构造函数,标识该构造函数为工厂模式,仅仅只是一个标识,具体功能还需要手动实现,如:从缓存中获取一个实例,在工厂构造函数中无法访问 this
class P {
final int id;
String? name;
int? age;
int? gender;
static final Map<int, P> _cache = {};
factory P.cache(int id) {
return _cache.putIfAbsent(id, () => P._internal(id));
}
P._internal(this.id, {this.name, this.age, this.gender});
}
main() {
P p1 = P.cache(0);
P p2 = P.cache(0);
print(identical(p1, p2));
}
运行结果:
5.成员函数
成员函数为在类内部定义的方法,除了常规函数的功能外,成员函数还支持下面的内容
5.1 operator 操作符重载
我们可以通过operator
去自定义自己类的+
、-
、*
等操作符,支持的操作符如下:
< | + | ` | ` |
> | / | ^ | [] |
<= | ~/ | & | []= |
>= | * | << | ~ |
- | % | >> | == |
下面例子重载了减法:
class Point {
double x, y;
Point(this.x, this.y);
// - 法重载
operator -(Point p2) => Point(x - p2.x, y - p2.y);
String toString() {
return 'Point{x: $x, y: $y}';
}
}
main() {
Point p1 = Point(4, 5);
Point p2 = Point(2, 3);
p1 -= p2;
print(p1);
}
运行结果:
5.2 Getter 和 Setter
Getter 和 Setter 是一对用来读写对象属性的特殊方法,每一个成员变量都有一个隐式的 Getter 方法,如果为非 final 属性的话还会有一个 Setter 方法,你可以使用 get
和 set
关键字为额外的属性添加 Getter 和 Setter 方法
class Rectangle {
double left, top, width, height;
Rectangle(this.left, this.top, this.width, this.height);
double get right => left + width;
set right(double value) => left = value - width;
double get bottom => top + height;
set bottom(double value) => top = value - height;
}
main(){
Rectangle rectangle = Rectangle(10, 30, 100, 200);
print("right:${rectangle.right} bottom:${rectangle.bottom}");
}
运行结果:
二、抽象类与接口
1. 抽象类
使用abstract
修饰类,让该类成为抽象类,抽象类中方法可以不实现,交由子类实现,称为抽象方法
abstract class P {
void call();// 抽象方法不需要实现
}
一般情况下,抽象类不可以实例化,使用factory
定义工厂构造函数后可被实例化
abstract class P {
P();
factory P.getDefault() => DP();
void call();
}
class DP extends P {
void call() {
print("hi");
}
}
main() {
P.getDefault().call();
}
2.接口
Dart只能继承一个父类,但在Dart中,每一个类都隐式地定义了一个接口并实现了该接口,这个接口包含所有这个类的成员变量的Getter 和 Setter函数与类成员函数,使用implements
可以实现多个接口
// P 作为接口
class P {
String name;
P(this.name);
call() => "hi";
}
class B implements P {
// 实现name的Getter 和 Setter
String get name => "B";
set name(String value) => name = value;
// call方法
call() {
print("hello");
}
}
三、枚举类
枚举类使用enum
关键字定义,你可以在 Switch 语句
中直接使用枚举
1.简单枚举
没有成员变量与函数的枚举
enum Color { red, green, blue }
2.增强枚举
除了简单枚举外,Dart还支持含有成员变量与函数的枚举,用法和类类似,其成员变量必须为final
,构造函数使用const
修饰。
enum Vehicle implements Comparable<Vehicle> {
car(tires: 4, passengers: 5, carbonPerKilometer: 400),
bus(tires: 6, passengers: 50, carbonPerKilometer: 800),
bicycle(tires: 2, passengers: 1, carbonPerKilometer: 0);
const Vehicle({
required this.tires,
required this.passengers,
required this.carbonPerKilometer,
});
final int tires;
final int passengers;
final int carbonPerKilometer;
int get carbonFootprint => (carbonPerKilometer / passengers).round();
int compareTo(Vehicle other) => carbonFootprint - other.carbonFootprint;
}
四、Mixin模板类
Mixin
是一种在多重继承中复用某个类中代码的方法模式。一个类可以使用with
指定一个或多个模板类,他类似于将Mixin
类中的代码直接复制一份到该类中
1.mixin 定义模板类
使用mixin
关键字,定义一个模板类
// 定义mixin
mixin Logger {
bool isDebug = true;
i(String info) {
if (isDebug) {
print(info);
}
}
}
// 使用mixin
class Hi with Logger {
Hi() {
i("constructor Hi()");
}
}
main(){
Hi();
}
运行结果:
2.on 指定可以使用的类
定义Mixin
类时,可以通过on
指定哪些类可以使用该模板
class Debugger {}
// 定义mixin 只有Debugger的子类才能使用
mixin Logger on Debugger {
bool isDebug = true;
i(String info) {
if (isDebug) {
print(info);
}
}
}
// 使用mixin
class Hi extends Debugger with Logger {
Hi() {
i("constructor Hi()");
}
}