Dart_基础_类

Dart 只能单继承,但是可以多层继承。

调用成员变量

操作符几乎和别的语言类似,提个比较特殊的赋值操作符 ??= 和 ?.操作符:

var a = 1;
var b;
b ?? = a; // 如果 b 的值是 null 则将 a 赋值给 b,否则保持不变
var c = size?.x; // 如果 size 为 null 则返回 null,否则返回 size.a 的值

构造函数

使用

通过 构造函数 创建对象。 构造函数的名字可以是 *ClassName* 或者 *ClassName*.*identifier*。例如, 以下代码使用 a 和 a.instance() 构造函数创建 Point 对象:

var a1 = a(2, 2);
var a2 = a.instance({'x': 1, 'y': 2});
//在 Dart 2 中 new 关键字变成了可选的。
var a1 = new a(2, 2);
var a2 = new a.instance({'x': 1, 'y': 2});

常量构造函数

var a = const ImmutablePoint(1, 1);
var b = const ImmutablePoint(1, 1);

assert(identical(a, b)); // 它们是同一个实例。

常量上下文 中, 构造函数或者字面量前的 const 可以省略。 例如,下面代码创建了一个 const 类型的 map 对象:

// 这里有很多的 const 关键字。
const pointAndLine = const {
  'point': const [const ImmutablePoint(0, 0)],
  'line': const [const ImmutablePoint(1, 10), const ImmutablePoint(-2, 11)],
};

// 仅有一个 const ,由该 const 建立常量上下文。
const pointAndLine = {
  'point': [ImmutablePoint(0, 0)],
  'line': [ImmutablePoint(1, 10), ImmutablePoint(-2, 11)],
};
/**************************************************************************/
var a = const ImmutablePoint(1, 1); // 创建一个常量对象
var b = ImmutablePoint(1, 1); // 创建一个非常量对象

assert(!identical(a, b)); // 两者不是同一个实例!

构造函数

class Point {
  num x, y;

  Point(num x, num y) {
    // 还有更好的方式来实现下面代码,敬请关注。
    this.x = x;
    this.y = y;
  }
}
//两种创建方式一样
class Point {
  num x, y;

  // 在构造函数体执行前,
  // 语法糖已经设置了变量 x 和 y。
  Point(this.x, this.y);
}

默认构造函数

默认构造函数没有参数并会调用父类的无参构造函数。

构造函数不被继承

子类不会继承父类的构造函数。 子类不声明构造函数,那么它就只有默认构造函数 (匿名,没有参数) 。

命名构造函数

一个类可以实现多个构造函数:

class Point {
  num x, y;

  Point(this.x, this.y);

  // 命名构造函数
  Point.origin() {
    x = 0;
    y = 0;
  }
}

切记,构造函数不能够被继承, 这意味着父类的命名构造函数不会被子类继承。 如果希望使用父类中定义的命名构造函数创建子类, 就必须在子类中实现该构造函数。

初始化列表

// 在构造函数体执行之前,
// 通过初始列表设置实例变量。
Point.fromJson(Map 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)');
}

警告: 初始化程序的右侧无法访问 this

重定向构造函数

class Point {
  num x, y;

  // 类的主构造函数。
  Point(this.x, this.y);

  // 指向主构造函数
  Point.alongXAxis(num x) : this(x, 0);
}

常量构造函数

class ImmutablePoint {
  static final ImmutablePoint origin =
      const ImmutablePoint(0, 0);

  final num x, y;

  const ImmutablePoint(this.x, this.y);
}

工厂构造函数

当执行构造函数并不总是创建这个类的一个新实例时,则使用 factory 关键字。 例如,一个工厂构造函数可能会返回一个 cache 中的实例, 或者可能返回一个子类的实例。

class Logger {
  final String name;
  bool mute = false;

  // 从命名的 _ 可以知,
  // _cache 是私有属性。
  static final Map _cache =
      {};

  factory Logger(String name) {
    if (_cache.containsKey(name)) {
      return _cache[name];
    } else {
      final logger = Logger._internal(name);
      _cache[name] = logger;
      return logger;
    }
  }

  Logger._internal(this.name);

  void log(String msg) {
    if (!mute) print(msg);
  }
}
//工厂构造函的调用方式与其他构造函数一样:
var logger = Logger('UI');
logger.log('Button clicked');

提示: 工厂构造函数无法访问 this。

获取对象的类型

使用对象的 runtimeType 属性, 可以在运行时获取对象的类型, runtimeType 属性回返回一个 Type 对象。

实例变量

class Point {
  num x; // 声明示例变量 x,初始值为 null 。
  num y; // 声明示例变量 y,初始值为 null 。
  num z = 0; // 声明示例变量 z,初始值为 0 。
}

所有实例变量都生成隐式 getter 方法。 非 final 的实例变量同样会生成隐式 setter 方法。

方法

实例方法

import 'dart:math';

class Point {
  num x, y;

  Point(this.x, this.y);

  num distanceTo(Point other) {
    var dx = x - other.x;
    var dy = y - other.y;
    return sqrt(dx * dx + dy * dy);
  }
}

Getter 和 Setter

Dart 会为变量提供隐形 Getter 和 Setter ,但是也可以使用 getset 关键字实现 Getter 和 Setter :

class Rectangle {
  num left, top, width, height;

  Rectangle(this.left, this.top, this.width, this.height);

  // 定义两个计算属性: right 和 bottom。
  num get right => left + width;
  set right(num value) => left = value - width;
  num get bottom => top + height;
  set bottom(num value) => top = value - height;
}

void main() {
  var rect = Rectangle(3, 4, 20, 15);
  assert(rect.left == 3);
  rect.right = 12;
  assert(rect.left == -8);
}

提示: 类似 (++) 之类操作符不管是否定义了 getter 方法,都能够正确的执行。 为了避免一些问题,操作符只调用一次 getter 方法, 然后把值保存到一个临时的变量中。

抽象方法

同 Java 中的实现:

abstract class Doer {
  // 定义实例变量和方法 ...

  void doSomething(); // 定义一个抽象方法。
}

class EffectiveDoer extends Doer {
  void doSomething() {
    // 提供方法实现,所以这里的方法就不是抽象方法了...
  }
}

抽象类

使用 abstract 修饰符来定义 抽象类 — 抽象类不能实例化。 抽象类通常用来定义接口,以及部分实现。 如果希望抽象类能够被实例化,那么可以通过定义一个 工厂构造函数 来实现。

// 这个类被定义为抽象类,
// 所以不能被实例化。
abstract class AbstractContainer {
  // 定义构造行数,字段,方法...

  void updateChildren(); // 抽象方法。
}

隐式接口

同 Java 中的接口:

// person 类。 隐式接口里面包含了 greet() 方法声明。
class Person {
  // 包含在接口里,但只在当前库中可见。
  final _name;

  // 不包含在接口里,因为这是一个构造函数。
  Person(this._name);

  // 包含在接口里。
  String greet(String who) => 'Hello, $who. I am $_name.';
}

// person 接口的实现。
class Impostor implements Person {
  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()));
}

//实现多接口
class Point implements Comparable, Location {...}

扩展类(继承)

同 Java :

class Television {
  void turnOn() {
    _illuminateDisplay();
    _activateIrSensor();
  }
  // ···
}

class SmartTelevision extends Television {
  void turnOn() {
    super.turnOn();
    _bootNetworkInterface();
    _initializeMemory();
    _upgradeApps();
  }
  // ···
}

重写类成员

同 Java:

class SmartTelevision extends Television {
  @override
  void turnOn() {...}
  // ···
}

重写运算符

这个就很神器,用代码来说明吧,下面示例演示一个类重写 +- 操作符

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);

  // 运算符 == 和 hashCode 部分没有列出。 有关详情,请参考下面的注释。
  // ···
}

void main() {
  final v = Vector(2, 3);
  final w = Vector(2, 2);

  assert(v + w == Vector(4, 5));
  assert(v - w == Vector(0, 1));
}

可被重写的运算符

| < | + | | | [] |
| ---- | ---- | ---- | ----- |
| > | / | ^ | []= |
| <= | ~/ | & | ~ |
| >= | * | << | == |
| | % | >> | |

提示: 你可能会被提示 != 运算符为非可重载运算符。 因为 e1 != e2 表达式仅仅是 !(e1 == e2) 的语法糖。

noSuchMethod()

当代码尝试使用不存在的方法或实例变量时, 通过重写 noSuchMethod() 方法,来实现检测和应对处理:

class A {
  // 如果不重写 noSuchMethod,访问
  // 不存在的实例变量时会导致 NoSuchMethodError 错误。
  @override
  void noSuchMethod(Invocation invocation) {
    print('You tried to use a non-existent member: ' +
        '${invocation.memberName}');
  }
}

枚举类型

同 Java:

enum Color { red, green, blue }
//枚举中存在一个值 index 返回值为枚举类型定义中的位置 
assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);
//使用 values  获取所有枚举值列表( list )
List colors = Color.values;
assert(colors[2] == Color.blue);
//可以在 switch 语句 中使用枚举
var aColor = Color.blue;
switch (aColor) {
  case Color.red:
    print('Red as roses!');
    break;
  case Color.green:
    print('Green as grass!');
    break;
  default: // 没有这个,会看到一个警告。
    print(aColor); // 'Color.blue'
}

混入(Mixin)

这个理解起来不算难,我们写一个例子:

class S {
  a() {print("S.a");}
}

class A {
  a(){print("A.a");}
  b(){print("A.b");}
}

class B {
  a(){print("B.a");}
  b(){print("B.b");}
  c(){print("B.c ");}
}

class T = B with A, S;

main(List args) {
  T t = new T();
  t.a();
  t.b();
  t.c();
}

//输出
S.a
A.b
B.c 

静态

Dart 和 Java 中的静态是一样的;

你可能感兴趣的:(Dart_基础_类)