那些你不知道的Dart细节之类的点点滴滴(五)

释放双眼,带上耳机,听听看~!

前言

前几篇文章分别讲解了Dart中的变量、内置类型、函数(方法)、操作符、流程控制语句和异常,对Dart的基本语法已经有了很多的了解,那么今天来说一下Dart中的类。前几篇文章没有看的,建议先看一下前几篇文章。

那些你不知道的Dart细节之变量

那些你不知道的Dart细节之内置类型

那些你不知道的Dart细节之函数(方法)

那些你不知道的Dart细节之操作符、流程控制语句、异常

那些你不知道的Dart细节之类的点点滴滴

那些你不知道的Dart细节之泛型和库

构造函数

前几篇文章中在讲函数(方法)的一篇中提到过,这里再说一下吧,首先来看一下Java中构造函数的写法:


1
2
3
4
5
6
7
8
9
10
11
1class Point {
2  double x;
3  double y;
4
5  Point(int x, int y) {
6    this.x = x;
7    this.y = y;
8  }
9}
10
11

下面是dart中的建议写法:


1
2
3
4
5
6
7
1class Point {
2  num x;
3  num y;
4  Point(this.x, this.y);
5}
6
7

命名构造函数

使用命名构造函数可以为一个类实现多个构造函数, 或者使用命名构造函数来更清晰的表明你的意图。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
1class Point {
2  num x;
3  num y;
4
5  Point(this.x, this.y);
6
7  //命名构造函数
8  Point.fromJson(Map json) {
9    x = json['x'];
10    y = json['y'];
11  }
12}
13
14

重定向构造函数

一个重定向构造函数是没有代码的,在构造函数声明后,使用 冒号调用其他构造函数。


1
2
3
4
5
6
7
8
9
10
11
1class Point {
2  num x;
3  num y;
4
5  Point(this.x, this.y);
6
7  //重定向构造函数,使用冒号调用其他构造函数
8  Point.alongXAxis(num x) : this(x, 0);
9}
10
11

初始化列表

在构造函数体执行之前可以初始化实例参数。 使用逗号分隔初始化表达式。初始化列表非常适合用来设置 final 变量的值。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1import 'dart:math';
2
3class Point {
4  //final变量不能被修改,必须被构造函数初始化
5  final num x;
6  final num y;
7  final num distanceFromOrigin;
8
9  //初始化列表
10  Point(x, y)
11      : x = x,
12        y = y,
13        distanceFromOrigin = sqrt(x * x + y * y);
14}
15
16

调用超类构造函数

首先来建立一个超类(父类),下面的代码都继承自此类:


1
2
3
4
5
6
7
8
9
10
11
12
13
1class Parent {
2  int x;
3  int y;
4
5  //父类命名构造函数不会传递  
6  Parent.fromJson(x, y)
7      : x = x,
8        y = y {
9    print('父类命名构造函数');
10  }
11}
12
13
  • 超类命名构造函数不会传递,如果希望使用超类中定义的命名构造函数创建子类,则必须在子类中实现该构造函数。


1
2
3
4
5
6
7
8
9
10
11
12
1class Child extends Parent {
2  int x;
3  int y;
4
5  Child.fromJson(x, y)
6    : x = x,
7      y = y,
8    print('子类命名构造函数');
9  }
10}
11
12
  • 如果超类没有默认构造函数, 则你需要手动的调用超类的其他构造函数,调用超类构造函数的参数无法访问 this。


1
2
3
4
5
6
7
8
9
10
11
12
1class Child extends Parent {
2  int x;
3  int y;
4  //若超类没有默认构造函数, 需要手动调用超类其他构造函数
5  Child(x, y) : super.fromJson(x, y) {
6    //调用父类构造函数的参数无法访问 this
7    print('子类构造函数');
8  }
9}
10
11
12
  • 在构造函数的初始化列表中使用 super(),需要把它放到最后。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
1class Child extends Parent {
2  int x;
3  int y;
4
5  Child.fromJson(x, y)
6    : x = x,
7      y = y,
8      super.fromJson(x, y) {
9    print('子类命名构造函数');
10  }
11}
12
13
14

常量构造函数

定义const构造函数要确保所有实例变量都是final。
const关键字放在构造函数名称之前。


1
2
3
4
5
6
7
8
9
10
11
1class Point2 {
2  //定义const构造函数要确保所有实例变量都是final
3  final num x;
4  final num y;
5  static final Point2 origin = const Point2(0, 0);
6
7  //const关键字放在构造函数名称之前,且不能有函数体
8  const Point2(this.x, this.y);
9}
10
11

工厂构造函数(Dart中的单例)

工厂构造函数是一种构造函数,与普通构造函数不同,工厂函数不会自动生成实例,而是通过代码来决定返回的实例对象。如果一个构造函数并不总是返回一个新的对象(单例),则使用 factory 来定义这个构造函数。工厂构造函数无法访问this。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
1class Singleton {
2  String name;
3  //工厂构造函数无法访问this,所以这里要用static
4  static Singleton _cache;
5
6  //工厂方法构造函数,关键字factory
7  factory Singleton([String name = 'singleton']) =>
8      Singleton._cache ??= Singleton._newObject(name);
9
10  //定义一个命名构造函数用来生产实例
11  Singleton._newObject(this.name);
12}
13
14

Setter和Getter

在Java中get和set方法可以直接生成,在Dart中无需自己定义。每个实例变量都隐含的具有一个 getter, 如果变量不是 final 的则还有一个 setter。可以通过实行 getter 和 setter 来创建新的属性, 使用 get 和 set 关键字定义 getter 和 setter。可以开始使用实例变量,后来可以把实例变量用函数包裹起来,而调用你代码的地方不需要修改。下面是代码实例:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1class Rectangle {
2  num left;
3  num top;
4  num width;
5  num height;
6
7  Rectangle(this.left, this.top, this.width, this.height);
8
9  num get right => left + width;
10  set right(num value) => left = value - width;
11  num get bottom => top + height;
12  set bottom(num value) => top = value - height;
13}
14
15

抽象类(接口)

  • 不能被实例化,除非定义一个工厂构造函数。

这个很好理解,在Java中的抽象类也同样不可实例化。

  • 抽象类通常用来定义接口, 以及部分实现。

在Dart中没有interface这个关键字,只有abstract,所以可以使用abstract来生成接口:


1
2
3
4
5
6
7
8
9
10
1abstract class Demo{
2  void zhujiang();
3}
4
5class Zhu implements Demo{
6  @override
7  void zhujiang() {}
8}
9
10
  • 抽象类通常具有抽象方法,抽象方法不需要关键字,以分号结束即可。

其实上面代码也可以用作这个实例,只需要把implements变成extends即可:


1
2
3
4
5
6
1class Zhu extends Demo{
2  @override
3  void zhujiang() {}
4}
5
6
  • 接口方式使用时,需要重写抽象类的成员变量和方法,包括私有的。

  • 一个类可以implement一个普通类。Dart任何一个类都是接口。

  • 一个类可以implement多个接口。

最后几个说的其实有点绕,说白了就是可以实现多个,这里需要注意的是:implement只是实现接口,你需要重写接口中的方法,不然是不会执行的。还有一点是如果想extents多个类的话需要使用with关键字。说了这么多不如直接看代码,看代码应该好理解一些:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1abstract class Demo{
2  void zhujiang();
3}
4
5abstract class Demo2{
6  void zhujiang();
7}
8
9abstract class Demo3{
10  void zhujiang();
11}
12
13class Zhu extends Demo with Demo2,Demo3 implements Demo3,Demo2{
14  @override
15  void zhujiang() {}
16}
17
18

可调用类

实现call()方法可以让类像函数一样能够被调用。这个很简单,直接上代码:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
1class ClassFunction {
2  call(String a, String b, String c) => '$a $b $c!';
3}
4
5main() {
6  var cf = new ClassFunction();
7  var out = cf("aaa","flutter","damon");
8  print('$out');
9  print(cf.runtimeType);
10  print(out.runtimeType);
11  print(cf is Function);
12}
13
14

下面是打印结果:


1
2
3
4
5
6
7
1lib/5.dart: Warning: Interpreting this as package URI, 'package:darttest/5.dart'.
2aaa flutter damon!
3ClassFunction
4String
5false
6
7

Mixin

  • 子类没有重写超类A方法的前提下,如果2个或多个超类拥有相同签名的A方法,那么子类会以继承的最后一个超类中的A方法为准。
  • 如果子类自己重写了A方法则以本身的A方法为准。

在这里先不过多解释Minxin,我的理解就类似于策略模式,抽出不变的为接口,然后多实现。这里先不写了,如果有可能的话等专门写一篇介绍Dart中的Minxin的文章吧。

总结

到这里为止Dart的第五篇文章完成。本篇文章主要讲解了一下Dart语言的类。下一篇文章讲解一下Dart中的泛xing和导入库,希望大家能够喜欢,对大家如果有帮助的话,欢迎点赞关注,如果有异议,可以留言进行讨论。

给TA打赏
共{{data.count}}人
人已打赏
安全技术

C++ explicit关键字

2022-1-11 12:36:11

安全漏洞

避免 Win 7 0day 漏洞,谷歌建议升级 Win 10

2019-3-10 11:12:22

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索