ClassName()
默认构造函数ClassName(…)
普通构造函数(无名或无参)ClassName.identifier()
命名构造函数(有参或无参)const ClassName(…)
常量构造函数factory ClassName(…)
工厂构造函数如果定义了一个类,在没有自定义其他构造函数的前提下,那么该类会有一个默认的构造函数,并且该函数没有名称也没有参数。
tips: 如果自定义了任何形式的构造函数,那么不会生成默认构造函数。
class Animal {
double weight;
double height;
}
void main() {
Animal animal = Animal(); // 调用默认构造函数
animal.height = 180;
animal.weight = 100;
}
普通构造函数也没有函数名,可以定义参数或者无参数。
tips: 显式定义的无参普通构造函数和默认的构造函数形式一样。这里主要在继承时需要注意一下,下面的继承段落会阐述。
使用如下:
class Animal {
double weight;
double height;
/// 定义普通构造函数
Animal(double weight, double height) {
this.weight = weight;
this.height = height;
}
}
void main() {
Animal animal = Animal(100, 180);
}
如果类有多个成员变量,那么使用 this.ivar = value
的形式显得很繁琐,所以dart
提供了语法糖,使用如下:
class Animal {
double weight;
double height;
Animal(this.weight, this.height);
}
void main() {
Animal animal = Animal(100, 180);
}
指定函数名称,然后可以添加参数或者无参数,也可以使用上述的语法糖,使用如下:
class Animal {
double weight;
double height;
Animal.initial(this.weight, this.height);
}
void main() {
Animal animal = Animal.initial(100, 180);
}
如果你希望你的实例对象创建出来后是不可改变的,那么可以定一个常量构造函数,在编译期就创建这个常量实例。
需要注意的点:
final
修饰的。const
进行修饰。使用如下:
:为了确保创建的常量实例不可变,在调用时可以使用const
进行修饰。
class Animal {
final double weight;
final double height;
/// 使用const进行修饰
const Animal(this.weight, this.height);
}
void main() {
const Animal animal = Animal(100, 180);
}
工厂构造函数的定义为每一次调用构造函数时,并不是都新建一个实例对象。
常用场景:
class Logger {
final String name;
bool mute = false;
// _cache is library-private, thanks to
// the _ in front of its name.
static final Map<String, Logger> _cache =
<String, Logger>{};
factory Logger(String name) {
if (_cache.containsKey(name)) {
return _cache[name];
} else {
final logger = Logger._internal(name);
_cache[name] = logger;
return logger;
}
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
main() {
var logger = Logger('UI');
logger.log('Button clicked');
}
工厂构造函数根据传入的name
为key
,从_cache
中寻找,如果有对应_key
,则返回对应的logger
对象。如果没有的话,则调用私有命名构造函数 Logger_internal(this.name)
。
使用如下:
class Animal {
Animal._initial();
static final Animal _instance = Animal._initial();
factory Animal() {
return _instance;
}
}
void main() {
/// animal为单例对象
Animal animal = Animal();
}
构造函数可以进行传递,直接在小括号后面使用":
",然后使用this
调用其他的构造函数。
使用如下:
class Animal {
Animal.initial() {
print('animal inital');
}
Animal.create() : this.initial();
}
main() {
Animal animal = Animal.create();
}
/// print result: animal inital
规则如下:
dart默认帮子类自动调用父类的无名无参构造函数。
自定手动调用父类的构造函数。
父类有默认构造函数或者自定义了无名无参构造函数时,子类会自动继承父类的无名无参构造函数。
并且在子类调用任何形式的构造函数时,都会自动调用父类的无名无参构造函数。
父类没有自定义构造函数时:
class Animal {}
class Dog extends Animal {
Dog() {
print('dog');
}
}
main() {
Dog dog = Dog();
}
///print result: dog
因为子类必须调用父类的构造函数,所以这里是自动调用了父类的默认构造函数。
父类自定义了无名无参构造函数时:
class Animal {
/// 自定义无名无参构造函数
Animal() {
print('animal');
}
/// 自定义命名构造函数
Animal.initial() {
print('animal initial');
}
}
class Dog extends Animal {
Dog() {
print('dog');
}
}
main() {
Dog dog = Dog();
}
/// print result: animal
/// print result: dog
父类存在无名无参构造函数,子类调用其他构造函数时:
class Animal {
Animal() {
print('animal');
}
Animal.initial() {
print('animal initial');
}
}
class Dog extends Animal {
Dog.initial() {
print('dog initial');
}
}
main() {
Dog dog = Dog.initial();
}
/// print result: animal
/// print result: dog initial
这里需要提到一个初始化列表,这里仅简单的介绍。
子类在调用构造函数时的顺序是:
子类手动调用父类的构造函数就是需要在初始化列表中调用,格式为构造函数小括号后添加分号":
" ,然后使用super
调用。
使用如下:
class Animal {
Animal.initial() {
print('animal initial');
}
Animal.create() {
print('animal create');
}
}
class Dog extends Animal {
Dog() : super.initial();
Dog.initial() : super.create();
}
main() {
Dog dog1 = Dog(); /// print result: animal initial
Dog dog2 = Dog.initial(); /// print result: animal create
}
初始化列表执行在构造函数之前,除了可以调用父类的构造函数之外,还可以初始化一些成员变量。初始化成员变量和调用父类的构造函数之间使用逗号","分隔。
特别是对于final
修饰的成员变量,final
变量在构造函数中是已经不能进行修改的。那么就可以在初始化列表中进行初始化。
使用如下:
class Animal {
final double height;
final double weight;
Animal.initial(double weight, double height)
: height = height,
weight = weight {
print('animal initial');
}
}
main() {
Animal animal = Animal.initial(100, 180);
}
初始化列表中还可以进行性aseert
添加判断等应用。
后续文章中进行详细的记录。