- 一些类提供了常量构造函数。使用常量构造函数,在构造函数名之前加
const
关键字,来创建编译时常量时:
class ImmutablePoint {
final int? x;
final int? y;
const ImmutablePoint(this.x, this.y);
}
- 下面代码中的 p1 和 p2 的执行结果是true, 它们其实是同一个实例
var p1 = const ImmutablePoint(1, 1);
var p2 = const ImmutablePoint(1, 1);
assert(p1 == p2);
- 在 常量上下文 场景中,你可以省略掉构造函数或字面量前的
const
关键字。例如下面的例子中我们创建了一个常量 Map:
const pointAndLine = const{
'point': const[const ImmutablePoint(1, 1)],
'line': const[const ImmutablePoint(1, 10), const ImmutablePoint(1, 11)],
};
- 根据上下文,可以只保留一个
const
关键字,其余的全部省略:
const pointAndLine = {
'point': [ImmutablePoint(1, 1)],
'line': [ImmutablePoint(1, 10), ImmutablePoint(1, 11)],
};
- 但是如果无法根据上下文判断是否可以省略
const
,则不能省略掉const
关键字,否则将会创建一个 非常量对象 例如:
var p1 = const ImmutablePoint(1, 1);
var p2 = ImmutablePoint(1, 1);
assert(p1 == p2);
- 上面代码执行结果会抛出异常:
如果你没有声明构造函数,那么 Dart 会自动生成一个无参数的 构造函数并且该构造函数会调用其父类的 无参数构造方法。
子类不会继承父类的构造函数,如果子类没有声明构造函数,那么只会有一个默认无参数的构造函数。
可以为一个类声明多个命名式构造函数来表达更明确的意图:
class Point {
final int? x; // int? 可空类型
final int? y;
Point(this.x, this.y);
// 命名构造函数,上面讲过
Point.origin()
: x = xOrigin,
y = yOrigin;
}
记住构造函数是不能被继承的,这将意味着子类不能继承父类的命名式构造函数,如果你想在子类中提供一个与父类命名构造函数名字一样的命名构造函数,则需要在子类中显式地声明。
默认情况下,子类的构造函数会调用父类的匿名无参数构造方法,并且该调用会在子类构造函数的函数体代码执行前,如果子类构造函数还有一个
初始化列表,那么该初始化列表会在调用父类的该构造函数之前被执行,总的来说,这三者的调用顺序如下:
-
初始化列表
-
父类的无参数构造函数
-
当前类的构造函数
如果父类没有匿名无参数构造函数,那么子类必须调用父类的其中一个构造函数,为子类的构造函数指定一个父类的构造函数只需在构造函数体前使用(:)指定。
下面的示例中,Employee 类的构造函数调用了父类 Person 的命名构造函数。
class Person{
String? firstName;
Person.formJson(Map map){
print("进入了Person 的命名函数中、、、");
}
}
class Employee extends Person{
// Person没有默认构造函数;
//你必须重新Employee.formJson 并调用 super.fromJson(data)。
Employee.formJson(Map map) : super.formJson(map){
print("进入了 Employee 子类");
}
}
main{
var employee = Employee.formJson({});
print(employee);
}
上面实例代码打印如下:
因为参数会在子类构造函数被执行前传递给父类的构造函数,因此该参数也可以是一个表达式,比如一个函数:
class Employee extends Person {
Employee() : super.fromJson(fetchDefaultData());
// ···
}
可以使用
Object
对象的runtimeType
属性在运行时获取一个对象的类型,该对象类型是 Type 的实例。
print('p1 的实例类型是 ${p1.runtimeType}');
除了调用父类构造函数之外,还可以在构造函数体,执行之前初始化实例变量。每个实例变量之间使用逗号分隔。
class Point {
final int? x; // int? 可空类型
final int? y;
Point.fromJson(Map map)
: x = map['x'],
y = map['y'] {
print('In Point.fromJson(): ($x, $y)');
}
}
- 代码调用
Point.fromJson({'x': 2, 'y': 3});
- 运行结果如下:
- 在开发模式下,你可以在初始化列表中使用 assert 来验证输入数据:
Point.withAssert(this.x, this.y) : assert(x! > y!){
print('In Point.withAssert(): ($x, $y)');
}
上面代码中,如果 assert(x! > y!)
不为true,会直接抛出异常
- 使用初始化列表设置
final
字段非常方便,下面的示例中就使用初始化列表来设置了三个final
变量的值。
class Point {
final double? x; // int? 可空类型
final double? y;
final double distanceFromOrigin;
Point(double x, double y)
: x = x,
y = y,
distanceFromOrigin = (x * x + y * y);
}
main{
var p = Point(2, 5);
print(p.distanceFromOrigin);
}
运行结果为:
有时候类中的构造函数仅用于调用类中其它的构造函数,此时该构造函数没有函数体,只需在函数签名后使用(:)指定需要重定向到的其它构造函数 (使用
this
而非类名):
class Point{
double x, y;
// this 主构造函数
Point(this.x, this.y);
Point.alongXAxis(double x): this(x, 0);
}
main{
var p = Point(2, 5);
print(p.y);
print(p.x);
var p1 = Point.alongXAxis(10);
print(p1.y);
print(p1.x);
}
运行结果如下:
使用
factory
关键字标识类的构造函数将会令该构造函数变为工厂构造函数,这将意味着使用该构造函数构造类的实例时并非总是会返回新的实例对象。例如,工厂构造函数可能会从缓存中返回一个实例,或者返回一个子类型的实例。
- 在如下的示例中,
Logger
的工厂构造函数从缓存中返回对象,和Logger.fromJson
工厂构造函数从 JSON 对象中初始化一个最终变量。
class Logger{
final String name;
// 带有 _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);
}
- 工厂构造函数的调用方式与其他构造函数一样:
main{
var logger = Logger("tiger");
print(logger.name);
var logger2 = Logger.fromJson({'name': 'TIGER'});
print(logger2.name);
}
================================================================
文末
今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。
最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。
还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
【Android核心高级技术PDF文档,BAT大厂面试真题解析】
【算法合集】
【延伸Android必备知识点】
【Android部分高级架构视频学习资源】
**Android精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!
腾讯、头条、阿里、美团等公司2021年的面试题*,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。
还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
【Android核心高级技术PDF文档,BAT大厂面试真题解析】
[外链图片转存中…(img-X2NZFpIK-1718715407097)]
【算法合集】
[外链图片转存中…(img-Fp8uZc43-1718715407098)]
【延伸Android必备知识点】
[外链图片转存中…(img-IsNTcx36-1718715407098)]
【Android部分高级架构视频学习资源】
**Android精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!