前言
前几篇文章分别讲解了Dart中的变量、内置类型、函数(方法)、操作符、流程控制语句和异常,对Dart的基本语法已经有了很多的了解,那么今天来说一下Dart中的类。前几篇文章没有看的,建议先看一下前几篇文章。
Flutter高手秘籍之Dart变量
Flutter高手秘籍之Dart变量
Flutter高手秘籍之Dart内置类型
Flutter高手秘籍之Dart函数(方法)
Flutter高手秘籍之Dart操作符、流程控制语句、异常
Flutter高手秘籍之Dart类的点点滴滴
Flutter高手秘籍之Dart泛型和库
构造函数
前几篇文章中在讲函数(方法)的一篇中提到过,这里再说一下吧,首先来看一下Java中构造函数的写法:
class Point {
double x;
double y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
}
下面是dart中的建议写法:
class Point {
num x;
num y;
Point(this.x, this.y);
}
命名构造函数
使用命名构造函数可以为一个类实现多个构造函数, 或者使用命名构造函数来更清晰的表明你的意图。
class Point {
num x;
num y;
Point(this.x, this.y);
//命名构造函数
Point.fromJson(Map json) {
x = json['x'];
y = json['y'];
}
}
重定向构造函数
一个重定向构造函数是没有代码的,在构造函数声明后,使用 冒号调用其他构造函数。
class Point {
num x;
num y;
Point(this.x, this.y);
//重定向构造函数,使用冒号调用其他构造函数
Point.alongXAxis(num x) : this(x, 0);
}
初始化列表
在构造函数体执行之前可以初始化实例参数。 使用逗号分隔初始化表达式。初始化列表非常适合用来设置 final 变量的值。
import 'dart:math';
class Point {
//final变量不能被修改,必须被构造函数初始化
final num x;
final num y;
final num distanceFromOrigin;
//初始化列表
Point(x, y)
: x = x,
y = y,
distanceFromOrigin = sqrt(x * x + y * y);
}
调用超类构造函数
首先来建立一个超类(父类),下面的代码都继承自此类:
class Parent {
int x;
int y;
//父类命名构造函数不会传递
Parent.fromJson(x, y)
: x = x,
y = y {
print('父类命名构造函数');
}
}
-
超类命名构造函数不会传递,如果希望使用超类中定义的命名构造函数创建子类,则必须在子类中实现该构造函数。
class Child extends Parent { int x; int y; Child.fromJson(x, y) : x = x, y = y, print('子类命名构造函数'); } }
-
如果超类没有默认构造函数, 则你需要手动的调用超类的其他构造函数,调用超类构造函数的参数无法访问 this。
class Child extends Parent { int x; int y; //若超类没有默认构造函数, 需要手动调用超类其他构造函数 Child(x, y) : super.fromJson(x, y) { //调用父类构造函数的参数无法访问 this print('子类构造函数'); } }
-
在构造函数的初始化列表中使用 super(),需要把它放到最后。
class Child extends Parent { int x; int y; Child.fromJson(x, y) : x = x, y = y, super.fromJson(x, y) { print('子类命名构造函数'); } }
常量构造函数
定义const构造函数要确保所有实例变量都是final。
const关键字放在构造函数名称之前。
class Point2 {
//定义const构造函数要确保所有实例变量都是final
final num x;
final num y;
static final Point2 origin = const Point2(0, 0);
//const关键字放在构造函数名称之前,且不能有函数体
const Point2(this.x, this.y);
}
工厂构造函数(Dart中的单例)
工厂构造函数是一种构造函数,与普通构造函数不同,工厂函数不会自动生成实例,而是通过代码来决定返回的实例对象。如果一个构造函数并不总是返回一个新的对象(单例),则使用 factory 来定义这个构造函数。工厂构造函数无法访问this。
class Singleton {
String name;
//工厂构造函数无法访问this,所以这里要用static
static Singleton _cache;
//工厂方法构造函数,关键字factory
factory Singleton([String name = 'singleton']) =>
Singleton._cache ??= Singleton._newObject(name);
//定义一个命名构造函数用来生产实例
Singleton._newObject(this.name);
}
Setter和Getter
在Java中get和set方法可以直接生成,在Dart中无需自己定义。每个实例变量都隐含的具有一个 getter, 如果变量不是 final 的则还有一个 setter。可以通过实行 getter 和 setter 来创建新的属性, 使用 get 和 set 关键字定义 getter 和 setter。可以开始使用实例变量,后来可以把实例变量用函数包裹起来,而调用你代码的地方不需要修改。下面是代码实例:
class Rectangle {
num left;
num top;
num width;
num height;
Rectangle(this.left, this.top, this.width, this.height);
num get right => left + width;
set right(num value) => left = value - width;
num get bottom => top + height;
set bottom(num value) => top = value - height;
}
抽象类(接口)
-
不能被实例化,除非定义一个工厂构造函数。
这个很好理解,在Java中的抽象类也同样不可实例化。
-
抽象类通常用来定义接口, 以及部分实现。
在Dart中没有interface这个关键字,只有abstract,所以可以使用abstract来生成接口:
abstract class Demo{ void zhujiang(); } class Zhu implements Demo{ @override void zhujiang() {} }
-
抽象类通常具有抽象方法,抽象方法不需要关键字,以分号结束即可。
其实上面代码也可以用作这个实例,只需要把implements变成extends即可:
class Zhu extends Demo{ @override void zhujiang() {} }
-
接口方式使用时,需要重写抽象类的成员变量和方法,包括私有的。
-
一个类可以implement一个普通类。Dart任何一个类都是接口。
-
一个类可以implement多个接口。
最后几个说的其实有点绕,说白了就是可以实现多个,这里需要注意的是:implement只是实现接口,你需要重写接口中的方法,不然是不会执行的。还有一点是如果想extents多个类的话需要使用with关键字。说了这么多不如直接看代码,看代码应该好理解一些:
abstract class Demo{
void zhujiang();
}
abstract class Demo2{
void zhujiang();
}
abstract class Demo3{
void zhujiang();
}
class Zhu extends Demo with Demo2,Demo3 implements Demo3,Demo2{
@override
void zhujiang() {}
}
可调用类
实现call()方法可以让类像函数一样能够被调用。这个很简单,直接上代码:
class ClassFunction {
call(String a, String b, String c) => '$a $b $c!';
}
main() {
var cf = new ClassFunction();
var out = cf("aaa","flutter","damon");
print('$out');
print(cf.runtimeType);
print(out.runtimeType);
print(cf is Function);
}
下面是打印结果:
lib/5.dart: Warning: Interpreting this as package URI, 'package:darttest/5.dart'.
aaa flutter damon!
ClassFunction
String
false
Mixin
- 子类没有重写超类A方法的前提下,如果2个或多个超类拥有相同签名的A方法,那么子类会以继承的最后一个超类中的A方法为准。
- 如果子类自己重写了A方法则以本身的A方法为准。
在这里先不过多解释Minxin,我的理解就类似于策略模式,抽出不变的为接口,然后多实现。这里先不写了,如果有可能的话等专门写一篇介绍Dart中的Minxin的文章吧。
总结
到这里为止Dart的第五篇文章完成。本篇文章主要讲解了一下Dart语言的类。下一篇文章讲解一下Dart中的泛xing和导入库,希望大家能够喜欢,对大家如果有帮助的话,欢迎点赞关注,如果有异议,可以留言进行讨论。