我们再来看看dart的Class。
Classes
构造器
我们通过构造器创建对象。构造器名称可以是ClassName或者类ClassName.xxx。比如:创建Point对象,我们可以用 Point()
或者 Point.fromJson()
。
var p1 = Point(2, 2);
var p2 = Point.fromJson({'x': 1, 'y': 2});
构造器便捷初始化
class Point {
double x = 0;
double y = 0;
Point(double x, double y) {
this.x = x;
this.y = y;
}
}
等价于
class Point {
double x = 0;
double y = 0;
Point(this.x, this.y);
}
默认构造器
如果你没有声明构造器,那么会提供一个默认构造器,他是无参的,会调用父类的无参构造器。
构造器不继承
子类不会继承父类的构造器。
命名构造器
class Point {
final double x;
final double y;
// Named constructor
Point.origin(double xOrigin, double yOrigin) {
this.x = xOrigin;
this.y = yOrigin;
}
}
Initializer list
Initializer list可以在constructor body运行前初始化实例变量。
Point.fromJson(Map<String, double> json)
: x = json['x']!,
y = json['y']! {
print('In Point.fromJson(): ($x, $y)');
}
我们可以用这种函数来校验参数
Point.withAssert(this.x, this.y) : assert(x >= 0) {
print('In Point.withAssert(): ($x, $y)');
}
调用父类的非默认构造器
默认情况下,子类的构造器会调用父类的无参默认构造器。父类构造器会在子类构造器body的开始处调用。如果子类构造器使用了initializer list
,那么initializer list
会在父类构造器之前调用。执行顺序如下:
- initializer list
- 父类的无参构造器
- 子类构造器
如果父类没有无参构造器,你必须手动指定调用的父类构造器,指定方式如下:
class Person {
String? firstName;
Person.fromJson(Map data) {
print('in Person');
}
}
class Employee extends Person {
// Person没有默认构造器
// 所以我们需要手动指定子类调用的父类的构造器 super.fromJson(data).
Employee.fromJson(Map data) : super.fromJson(data) {
print('in Employee');
}
}
class Vector2d {
final double x;
final double y;
Vector2d(this.x, this.y);
}
class Vector3d extends Vector2d {
final double z;
// 调用父类构造器的便捷初始化方法,等价于
// Vector3d(final double x, final double y, this.z) : super(x, y);
Vector3d(super.x, super.y, this.z);
}
redirecting constructor
有时,有的构造器的目的只是调用同一个class中的另一个构造器。
redirecting constructor
的函数体是空的。用冒号指定代理的构造器。
class Point {
double x, y;
// The main constructor for this class.
Point(this.x, this.y);
// Delegates to the main constructor.
Point.alongXAxis(double x) : this(x, 0);
}
Constant constructors
如果你生成的对象永远不会改变,那么你可以让那些对象成为编译时常量(const)。所以你定义一个const
constructor,然后让所有的实例变量都是final。
class ImmutablePoint {
static const ImmutablePoint origin = ImmutablePoint(0, 0);
final double x, y;
const ImmutablePoint(this.x, this.y);
}
Factory constructors
用 factory
关键字修饰的构造器代表:这个构造器并不总是返回这个Class的新对象,比如:可能返回的是cache中的对象,或者返回的是这个class的子类。
methods
Instance methods
实例方法可以访问实例变量和this
import 'dart:math';
class Point {
final double x;
final double y;
Point(this.x, this.y);
double distanceTo(Point other) {
var dx = x - other.x;
var dy = y - other.y;
return sqrt(dx * dx + dy * dy);
}
}
运算符方法
下面是dart允许定义的运算符方法
< | + | ` | ` |
---|---|---|---|
> | / | ^ | [] |
<= | ~/ | & | []= |
>= | * | << | ~ |
– | % | >> | == |
class Vector {
final int x, y;
Vector(this.x, this.y);
Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
Vector operator -(Vector v) => Vector(x - v.x, y - v.y);
}
void main() {
final v = Vector(2, 3);
final w = Vector(2, 2);
assert(v + w == Vector(4, 5));
assert(v - w == Vector(0, 1));
}
Getters 和 setters
下面是getter和setter的定义
class Rectangle {
double left, top, width, height;
Rectangle(this.left, this.top, this.width, this.height);
// Define two calculated properties: right and bottom.
double get right => left + width;
set right(double value) => left = value - width;
double get bottom => top + height;
set bottom(double value) => top = value - height;
}
void main() {
var rect = Rectangle(3, 4, 20, 15);
assert(rect.left == 3);
rect.right = 12;
assert(rect.left == -8);
}
抽象方法
抽象方法只能出现在抽象类中。
abstract class Doer {
void doSomething(); // Define an abstract method.
}
class EffectiveDoer extends Doer {
void doSomething() {
}
}
抽象类
用abstract
关键字定义抽象类,通常抽象类用于定义接口。
abstract class AbstractContainer {
void updateChildren(); // Abstract method.
}
隐式的 interfaces
每个class都隐式的定义了一个interface,包含所有的instance members 和他实现的所有Interface。
如果你创建了class A,想要B的功能,但是又不想继承,那么可以实现接口B。
// A person. The implicit interface contains greet().
class Person {
// In the interface, but visible only in this library.
final String _name;
// Not in the interface, since this is a constructor.
Person(this._name);
// In the interface.
String greet(String who) => 'Hello, $who. I am $_name.';
}
// An implementation of the Person interface.
class Impostor implements Person {
String get _name => '';
String greet(String who) => 'Hi $who. Do you know who I am?';
}
String greetBob(Person person) => person.greet('Bob');
void main() {
print(greetBob(Person('Kathy')));
print(greetBob(Impostor()));
}
dart是没有interface来定义接口的,通常实现接口都是abstract class 的隐式接口来达到同样的效果。
继承
使用extends关键字来继承某个class
class Television {
void turnOn() {
_illuminateDisplay();
_activateIrSensor();
}
// ···
}
class SmartTelevision extends Television {
void turnOn() {
super.turnOn();
_bootNetworkInterface();
_initializeMemory();
_upgradeApps();
}
// ···
}
重载
使用 @override
重载方法
class Television {
// ···
set contrast(int value) {...}
}
class SmartTelevision extends Television {
set contrast(num value) {...}
// ···
}
noSuchMethod()
重载noSuchMethod方法来检测是否调用了没有的方法。
class A {
// Unless you override noSuchMethod, using a
// non-existent member results in a NoSuchMethodError.
void noSuchMethod(Invocation invocation) {
print('You tried to use a non-existent member: '
'${invocation.memberName}');
}
}
Extension
类似swift的extension,可以在不知道源码的情况下为对象添加方法,不能添加实例变量。可以添加静态方法和静态变量,但是不能直接在原Class上直接调用,需要用Extension的名字调用。
extension NumberParsing on String {
int parseInt() {
return int.parse(this);
}
double parseDouble() {
return double.parse(this);
}
}
class Person {
var age = 0;
}
extension PersonExtension on Person {
static void sayHello() {
print("age is ");
}
static var address = "";
}
PersonExtension.sayHello();// extension 名称下调用
PersonExtension.address;// extension 名称下调用
枚举类型
声明简单枚举
enum Color { red, green, blue }
我们没办法直接像其他语言一样给枚举赋值,比如在swift中,我们可以这样
enum Color : Int {
red = 100
blue = 200
yellow = 300
}
//我们可以通过添加方法来达到同样的效果
enum Color {
red,
blue,
yellow;
int value() {
switch (this) {
case Color.red:
return 100;
case Color.blue:
return 200;
case Color.yellow:
return 300;
}
}
}
//或者使用之后的增强枚举
enum Color {
red(100),
blue(200),
yellow(300);
const Color(this.value);
final int value;
}
声明增强枚举
dart允许枚举像class一样定义实例变量、方法和常量构造器。但是有些限制:
- 实例变量必须都是
final
- 定义的构造器都必须是 const constructor。
- Factory constructors只能返回固定的已知的枚举实例。
- 不能继承
- 不能重载
index
,hashCode
,==
. - 不能定义
values
, 因为会和自动生成的staticvalues
getter冲突 - 枚举必须定义在开始位置。
enum Vehicle implements Comparable<Vehicle> {
car(tires: 4, passengers: 5, carbonPerKilometer: 400),
bus(tires: 6, passengers: 50, carbonPerKilometer: 800),
bicycle(tires: 2, passengers: 1, carbonPerKilometer: 0);
const Vehicle({
required this.tires,
required this.passengers,
required this.carbonPerKilometer,
});
final int tires;
final int passengers;
final int carbonPerKilometer;
int get carbonFootprint => (carbonPerKilometer / passengers).round();
int compareTo(Vehicle other) => carbonFootprint - other.carbonFootprint;
}
使用枚举
/// 有index
assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);
//values获取所有枚举
List<Color> colors = Color.values;
assert(colors[2] == Color.blue);
//获取枚举名称
print(Color.blue.name); // 'blue'
mixin
定义
mixin Musical {
bool canPlayPiano = false;
bool canCompose = false;
bool canConduct = false;
void entertainMe() {
if (canPlayPiano) {
print('Playing piano');
} else if (canConduct) {
print('Waving hands');
} else {
print('Humming to self');
}
}
}
使用
with
关键字
class Musician extends Performer with Musical {
// ···
}
现在mixin使用类型
class Musician {
// ...
}
mixin MusicalPerformer on Musician {
// ...
}
class SingerDancer extends Musician with MusicalPerformer {
// ...
}
类变量和类方法
class Queue {
static const initialCapacity = 16;
// ···
}
void main() {
assert(Queue.initialCapacity == 16);
}
import 'dart:math';
class Point {
double x, y;
Point(this.x, this.y);
static double distanceBetween(Point a, Point b) {
var dx = a.x - b.x;
var dy = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}
}
void main() {
var a = Point(2, 2);
var b = Point(4, 4);
var distance = Point.distanceBetween(a, b);
assert(2.8 < distance && distance < 2.9);
print(distance);
}