print(point.y);
* 使用 ?. 代替. 可以避免因为左边表达式为null 而导致的问题 (这个是flutter 2.0 之后新增的空认证功能)
print(point?.x);
print(point?.y);
* 如下代码所示`p1.y = 6;` **setter** 写入方法, `print(p1.y);` **getter** 读取方法
p1.y = 6;
print(p1.y);
[]( )2、构造函数
--------------------------------------------------------------------
> 可以使用 **构造函数** 来创建一个对象。构造函数的命名方式可以为 `类名` 或 `类名 . 标识符` 的形式。例如下述代码分别使用
> `Point()` 和 `Point.fromJson()` 两种构造器创建了 `Point` 对象:
class Point {
int? x;
int? y;
Point(this.x, this.y);
Point.fromJson(Map map) {
x = map['x'];
y = map['y'];
}
}
* 下面两段代码,执行的结果都是获取的对应的**x** 的值
var p1 = Point(2, 3);
print(p1.x);
var p2 = Point.fromJson({'x': 2, 'y': 3});
print(p2.x);
[]( )3、常量构造函数
----------------------------------------------------------------------
> 实例变量可以是`final`,在这种情况下,它们必须只设置一次。在声明时,使用构造函数形参或构造函数的初始化列表初始化最终的**非延迟实例变量**:
class ProfileMark{
final String name;
final DateTime start = DateTime.now();
ProfileMark(this.name);
ProfileMark.unNamed() : name = '';
}
* 一些类提供了**常量构造函数**。使用常量构造函数,在构造函数名之前加 `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);
* 上面代码执行结果会抛出异常:
![在这里插入图片描述](https://img-blog.csdnimg.cn/146143e1359f434b835a589d03ae5bdf.png)
[]( )4、默认构造函数
----------------------------------------------------------------------
> 如果你没有声明构造函数,那么 Dart 会自动生成一个无参数的 构造函数并且该构造函数会调用其父类的 无参数构造方法。
[]( )5、构造函数不被继承
------------------------------------------------------------------------
> 子类不会继承父类的构造函数,如果子类没有声明构造函数,那么只会有一个默认无参数的构造函数。
[]( )6、命名式构造函数
-----------------------------------------------------------------------
> 可以为一个类声明多个命名式构造函数来表达更明确的意图:
class Point {
final int? x; // int? 可空类型
final int? y;
Point(this.x, this.y);
// 命名构造函数,上面讲过
: x = xOrigin,
y = yOrigin;
}
> 记住构造函数是不能被继承的,这将意味着子类不能继承父类的命名式构造函数,如果你想在子类中提供一个与父类命名构造函数名字一样的命名构造函数,则需要在子类中显式地声明。
[]( )7、调用父类非默认构造函数
---------------------------------------------------------------------------
> 默认情况下,子类的构造函数会调用父类的匿名无参数构造方法,并且该调用会在子类构造函数的函数体代码执行前,如果子类构造函数还有一个
> 初始化列表,那么该初始化列表会在调用父类的该构造函数之前被执行,总的来说,这三者的调用顺序如下:
1. 初始化列表
2. 父类的无参数构造函数
3. 当前类的构造函数
如果父类没有匿名无参数构造函数,那么子类必须调用父类的其中一个构造函数,为子类的构造函数指定一个父类的构造函数只需在构造函数体前使用(:)指定。
下面的示例中,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);
}
上面实例代码打印如下:
![在这里插入图片描述](https://img-blog.csdnimg.cn/4365dd3e03d149f9840c9c09bb57dcfc.png)
因为参数会在子类构造函数被执行前传递给父类的构造函数,因此该参数也可以是一个表达式,比如一个函数:
class Employee extends Person {
Employee() : super.fromJson(fetchDefaultData());
// ···
}
[]( )8、获取对象的类型
-----------------------------------------------------------------------
> 可以使用 `Object` 对象的 `runtimeType` 属性在运行时获取一个对象的类型,该对象类型是 Type 的实例。
print('p1 的实例类型是 ${p1.runtimeType}');
[]( )9、初始化列表
---------------------------------------------------------------------
> 除了调用父类构造函数之外,还可以在构造函数体,执行之前初始化实例变量。每个实例变量之间使用逗号分隔。
class Point {
final int? x; // int? 可空类型
final int? y;
: x = map['x'],
y = map\['y'\] {
print('In Point.fromJson(): ($x, $y)');
}
}
* 代码调用
Point.fromJson({'x': 2, 'y': 3});
* 运行结果如下:
![在这里插入图片描述](https://img-blog.csdnimg.cn/10cd3a2ce65e44e9b8175c83d404c6a3.png)
* 在开发模式下,你可以在初始化列表中使用 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;
: x = x,
y = y,
distanceFromOrigin = (x \* x + y \* y);
}
main{
var p = Point(2, 5);
print(p.distanceFromOrigin);
}
运行结果为:
![在这里插入图片描述](https://img-blog.csdnimg.cn/3514bd19b56b49cdba4470d8e41b2b4b.png)
[]( )10、重定向构造函数
------------------------------------------------------------------------
> 有时候类中的构造函数仅用于调用类中其它的构造函数,此时该构造函数没有函数体,只需在函数签名后使用(:)指定需要重定向到的其它构造函数 (使用
> `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);
}
运行结果如下:
![在这里插入图片描述](https://img-blog.csdnimg.cn/40381dba452248a7900d3e7db8f32f45.png)
[]( )11、工厂构造函数
-----------------------------------------------------------------------
> 使用 `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));
}