目录
类
构造函数
命名构造函数
重定向构造函数
常量构造函数
工厂构造函数
Getters 和 Setters
初始化列表
可覆写的操作符
类
创建一个dart文件,名称全小写,里面的类可以按照驼峰命名法。文件名和类名可以不保持统一,这个跟Java有明显区别。
Dart是一种面向对象的语言,具有类和基于mixin
的继承。每个对象都是一个类的实例,所有的类都是Object的子类
。基于mixin的继承意味着,尽管每个类(除了Object)都只有一个超类
,但类主体可以在多个类层次结构中重用
。
示例中向你展示了一个包含2个属性、2个构造函数以及1个函数的类。
//每个实例变量都会自动生成一个 getter 方法(隐含的)。 非final 实例变量还会自动生成一个 setter 方法。
class SccPoint{
late num x;
num y;
//构造函数
SccPoint(this.x,this.y);
//命名构造函数
//Dart 不支持构造函数的重载
SccPoint.y(this.y){
x = 0;
}
//函数
void position(){
print("x=$x,y=$y");
}
}
构造函数
由于把构造函数参数赋值给实例变量的场景太常见了, Dart 提供了一个语法糖来简化这个操作:
//构造函数
SccPoint(this.x,this.y);
命名构造函数
Dart 不支持构造函数的重载
,而采用了命名构造函数为一个类实现多个构造函数:
//命名构造函数
//Dart 不支持构造函数的重载
SccPoint.y(this.y){
x = 0;
}
「运行结果」
重定向构造函数
有时候一个构造函数会调动类中的其他构造函数(在Java中就是 this(...)
)。 一个重定向构造函数是没有代码的,在构造函数声明后,使用 冒号调用其他构造函数。
class SccPoint{
num x;
num y;
//构造函数
SccPoint(this.x,this.y);
//命名构造函数
SccPoint.y(num y):this(0,y);//调用上面的构造函数
}
常量构造函数
如果你的类提供一个状态不变的对象
,你可以把这些对象 定义为编译时常量。要实现这个功能,需要定义一个 const
构造函数, 并且声明所有类的变量为 final
。
class ImmutablePoint {
final num x;
final num y;
//常量构造函数
const ImmutablePoint(this.x, this.y);
}
void main(){
//构造两个相同的编译时常量会生成一个单一的、规范的实例
var p3 = const ImmutablePoint(1,2);
var p4 = const ImmutablePoint(1,2);
print(p3 == p4); // true
print(identical(p3, p4));// true
}
工厂构造函数
当实现一个使用 factory
关键词修饰的构造函数时,这个构造函数不必创建类的新实例。例如,一个工厂构造函数 可能从缓存中获取一个实例并返回,或者 返回一个子类型的实例。(工厂构造函数无法访问 this
)
class Logger {
final String name;
bool mute = false;
// _cache 变量是库私有的,因为在其名字前面有下划线。
static final Map<String, Logger> _cache =
<String, Logger>{};
factory Logger(String name) {
return _cache.putIfAbsent(
name, () => Logger._internal(name)); //工厂构造函数里可以调用其他构造函数。
}
factory Logger.fromJson(Map<String, Object> json) {
return Logger(json['name'].toString());
}
//以 _ 开头的函数是库私有的,无法在库外使用
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
借助工厂构造函数能够实现单例:
//使用工厂构造实现单例
class Manager {
static final Manager _singleton = Manager._internal();
factory Manager() {
return _singleton;
}
Manager._internal();
}
//使用
var m1 = Manager();
var m2 = Manager();
print(m1 == m2); // true
Getters 和 Setters
Dart中每个实例变量都隐含的具有一个 getter, 如果变量不是 final 的则还有一个 setter。可以通过实现 getter 和 setter 来创建新的属性, 使用 get
和 set
关键字定义 getter 和 setter:
class SccPoint{
num x;
num y;
SccPoint(this.x,this.y);
void position(){
print("x=$x,y=$y,a=$a");
}
//使用 get定义了一个 a 属性(不可与原属性同名)
num get a => x+y;
set a(num b) => x=x+b;
}
void main() {
var p9 = SccPoint(3, 9);
p9.position();//x=3,y=9,a=12
p9.a=10;
p9.position();//x=13,y=9,a=22
}
注意:在get与set中使用自身会导致Stack Overflow(递归)
调用自身:
初始化列表
在构造函数函数体执行之前会首先执行初始化列表,非常适合用来设置 final 变量的值。
class SccPoint{
num? x;
num? y;
SccPoint.fromJson(Map<String, num> json)
: x = json['x'],
y = json['y'] {
print('In SccPoint.fromJson(): ($x, $y)');
}
}
//使用
SccPoint.fromJson({"x":15,"y":20});
可覆写的操作符
把已经定义的、有一定功能的操作符进行重新定义。可以重新定义的操作符有:
< | + | | | [] |
---|---|---|---|
> | / | ^ | []= |
<= | ~/ | & | ~ |
>= | * | << | == |
– | % | >> |
比如:dart.math包下Point类就重写了 +、-、*、==
这几个操作符。
Point<T> operator +(Point<T> other) {
return Point<T>((x + other.x) as T, (y + other.y) as T);
}
Point<T> operator *(num /*T|int*/ factor) {
return Point<T>((x * factor) as T, (y * factor) as T);
}
操作符重载函数的名字是“关键字 operator +以及紧跟其后的一个 Dart 预定义的操作符。
class SccPoint{
num x;
num y;
SccPoint(this.x,this.y);
//加
SccPoint operator +(SccPoint point){
return SccPoint(x+point.x,y+point.y);
}
//乘
SccPoint operator *(SccPoint point){
return SccPoint(x*point.x,y*point.y);
}
void position(){
print("x=$x,y=$y");
}
}
使用
//导入类文件(最好全路径),看起来直观一些
import 'package:flutter_demo_scc/scc_point.dart';
//导入类文件(相对路径),两种都可以
// import 'scc_point.dart';
void main() {
var p5 = SccPoint(3, 5);
var p6 = SccPoint(2, 7);
var p7 = p5+p6;
var p8 = p5*p6;
p5.position();//x=3,y=5
p6.position();//x=2,y=7
p7.position();//x=5,y=12
p8.position();//x=6,y=35
}