Dart 语言简易教程(六)

Dart 语言简易教程(一): http://www.jianshu.com/p/8a62b1a2fd75
Dart 语言简易教程(二): http://www.jianshu.com/p/b2153a32dd8b
Dart 语言简易教程(三): http://www.jianshu.com/p/6d2495a0d3d7
Dart 语言简易教程(四): http://www.jianshu.com/p/fdd046a6dc82
Dart 语言简易教程(五) http://www.jianshu.com/p/83adc77839b6

Dart 语言简易教程(六)

对象

Dart 是一种面向对象的语言,并且支持基于mixin的继承方式。
Dart 语言中所有的对象都是某一个类的实例。所有的类有同一个基类--Object。
基于mixin的继承方式具体是指:一个类可以继承自多个父类。

使用new语句来构造一个类。
构造函数的名字可能是ClassName,也可以是ClassName.identifier。例如:

var jsonData = JSON.decode('{"x":1, "y":2}');

// Create a Point using Point().
var p1 = new Point(2, 2);

// Create a Point using Point.fromJson().
var p2 = new Point.fromJson(jsonData);

使用.(dot) 来调用实例的变量或者方法。

var p = new Point(2, 2);

// Set the value of the instance variable y.
p.y = 3;

// Get the value of y.
assert(p.y == 3);

// Invoke distanceTo() on p.
num distance = p.distanceTo(new Point(4, 4));

使用?. 来确认前操作数不为空。常用来替代.

// If p is non-null, set its y value to 4.
p?.y = 4;

使用const替代new来创建编译时的常量构造函数。

var p = const ImmutablePoint(2, 2);

使用runtimeType方法,在运行中获取对象的类型。该方法将返回Type 类型的变量。

print('The type of a is ${a.runtimeType}');

实例化变量(Instance variables)

在类定义中,所有没有初始化的变量都会被初始化为null

class Point {
  num x; // Declare instance variable x, initially null.
  num y; // Declare y, initially null.
  num z = 0; // Declare z, initially 0.
}

类定义中所有的变量Dart 语言都会隐式的定义 setter 方法,针对非空的变量会额外增加 getter 方法。

class Point {
  num x;
  num y;
}

main() {
  var point = new Point();
  point.x = 4;          // Use the setter method for x.
  assert(point.x == 4); // Use the getter method for x.
  assert(point.y == null); // Values default to null.
}

构造函数(Constructors)

声明一个和类名相同的函数,来作为类的构造函数。

class Point {
  num x;
  num y;

  Point(num x, num y) {
    // There's a better way to do this, stay tuned.
    this.x = x;
    this.y = y;
  }
}

this关键字指向了当前类的实例。
上面的代码可以简化为:

class Point {
  num x;
  num y;

  // Syntactic sugar for setting x and y
  // before the constructor body runs.
  Point(this.x, this.y);
}

默认构造函数(Default constructors)

如果类定义时,没有显式的定义构造函数,Dart 语言将提供默认的构造函数。默认的构造函数没有参数。

构造函数不能继承(Constructors aren’t inherited)

Dart 语言中,子类不会继承父类的命名构造函数。如果不显式提供子类的构造函数,系统就提供默认的构造函数。

命名的构造函数(Named constructors)

使用命名构造函数从另一类或现有的数据中快速实现构造函数。

class Point {
  num x;
  num y;

  Point(this.x, this.y);

  // Named constructor
  Point.fromJson(Map json) {
    x = json['x'];
    y = json['y'];
  }
}

构造函数不能被继承,父类中的命名构造函数不能被子类继承。如果想要子类也拥有一个父类一样名字的构造函数,必须在子类是实现这个构造函数。

调用父类的非默认构造函数

默认情况下,子类只能调用父类的无名,无参数的构造函数。父类的无名构造函数会在子类的构造函数前调用。如果initializer list 也同时定义了,则会先执行initializer list 中的内容,然后在执行父类的无名无参数构造函数,最后调用子类自己的无名无参数构造函数。即下面的顺序:

  1. initializer list
  2. superclass’s no-arg constructor
  3. main class’s no-arg constructor

如果父类不显示提供无名无参数构造函数的构造函数,在子类中必须手打调用父类的一个构造函数。这种情况下,调用父类的构造函数的代码放在子类构造函数名后,子类构造函数体前,中间使用:(colon) 分割。

class Person {
  String firstName;

  Person.fromJson(Map data) {
    print('in Person');
  }
}

class Employee extends Person {
  // Person does not have a default constructor;
  // you must call super.fromJson(data).
  Employee.fromJson(Map data) : super.fromJson(data) {
    print('in Employee');
  }
}

main() {
  var emp = new Employee.fromJson({});

  // Prints:
  // in Person
  // in Employee
  if (emp is Person) {
    // Type check
    emp.firstName = 'Bob';
  }
  (emp as Person).firstName = 'Bob';
}

上面的代码输出如下:

in Person
in Employee
初始化器列表(Initializer list)

除了调用父类的构造函数,也可以通过Initializer list 在子类的构造函数运行前来初始化实例的变量值。如下所示:

import 'dart:math';

class Point {
  final num x;
  final num y;
  final num distanceFromOrigin;

  Point(x, y)
      : x = x,
        y = y,
        distanceFromOrigin = sqrt(x * x + y * y);
}

main() {
  var p = new Point(2, 3);
  print(p.distanceFromOrigin);
}

上面的代码运行结果为:

3.605551275463989

重定向构造函数

有时候构造函数的目的只是重定向到该类的另一个构造函数。
重定向构造函数的函数体是空的。

class Point {
  num x;
  num y;

  // The main constructor for this class.
  Point(this.x, this.y) {
    print("Point($x, $y)");
  }

  // Delegates to the main constructor.
  Point.alongXAxis(num x) : this(x, 0);
}

void main() {
  var p1 = new Point(1, 2);
  var p2 = new Point.alongXAxis(4);
}

上面代码对应的输出结果:

Point(1, 2)
Point(4, 0)

静态构造函数(Constant constructors)

如果类的对象不会发生变化,可以构造一个编译时的常量构造函数。
为了实现上述过程,定义格式如下:

  1. 将所有的类的变量定义为final 类型。
  2. 定义const 类型的构造函数。
class ImmutablePoint {
  final num x;
  final num y;
  const ImmutablePoint(this.x, this.y);
  static final ImmutablePoint origin =  const ImmutablePoint(0, 0);
}

工厂构造函数(Factory constructors)

factory 关键字的功能,当实现构造函数但是不想每次都创建该类的一个实例的时候使用。

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

  // _cache is library-private, thanks to the _ in front
  // of its name.
  static final Map<String, Logger> _cache =
  <String, Logger>{};

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

  Logger._internal(this.name);

  void log(String msg) {
    if (!mute) {
      print(msg);
    }
  }
}
void main() {
  var p1 = new Logger("1");
  p1.log("2");


  var p2 = new Logger("11");
  p2.log("21");

}

上面代码的输出结果:

2
21

方法(Methods)

方法是对象提供的函数功能。

Getters and Setters

get()set()方法是Dart 语言提供的专门用来读取和写入对象的属性的方法。
每一个类的实例,系统都隐式的包含有get()和set() 方法。
get()set()的例子:

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

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

  // Define two calculated properties: right and 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;
}

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

上面例子对应的输出为:

Observatory listening on http://127.0.0.1:33439
Unhandled exception:
'file:///opt/program/Dart/0910.dart': Failed assertion: line 20 pos 10: 'rect.left == -3' is not true.
#0      _AssertionError._throwNew (dart:core-patch/errors_patch.dart:27)
#1      _AssertionError._checkAssertion (dart:core-patch/errors_patch.dart:34)
#2      main (file:///opt/program/Dart/0910.dart:20:10)
#3      _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:261)
#4      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:148)

Process finished with exit code 255

抽象方法(Abstract methods)

抽象方法类似与Java语言中的interface 的概念。在当前不具体的实现方法,只是写好定义接口,具体实现留着调用的人去实现。
可以使用abstract关键字定义抽象方法。

抽象方法的例子:

abstract class Doer {
  // ...Define instance variables and methods...

  void doSomething(); // Define an abstract method.
}

class EffectiveDoer extends Doer {
  void doSomething() {
    // ...Provide an implementation, so the method is not abstract here...
  }
}

重载操作

1 2 3 4
< + []
> / ^ []=
<= ~/ & ~
>= * << ==
% >>

可以重载的操作符如下表所示:

1 2 3 4
< + []
> / ^ []=
<= ~/ & ~
>= * << ==
% >>

如果定义矢量的话,可以定义+ 方法我操作两个矢量的实例。

下面的例子就是重载了+-操作的例子:

class Vector {
  final int x;
  final int y;
  const Vector(this.x, this.y);

  /// Overrides + (a + b).
  Vector operator +(Vector v) {
    return new Vector(x + v.x, y + v.y);
  }

  /// Overrides - (a - b).
  Vector operator -(Vector v) {
    return new Vector(x - v.x, y - v.y);
  }
}

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

  // v == (2, 3)
  assert(v.x == 2 && v.y == 3);

  // v + w == (4, 5)
  assert((v + w).x == 4 && (v + w).y == 5);

  // v - w == (0, 1)
  assert((v - w).x == 0 && (v - w).y == 1);
}

如果重载了==,同时也需要重载对象的hashCodeget() 方法。

抽象类(Abstract classes)

使用abstract 关键字定义一个抽象类,抽象类是不能实例化的。
抽象类通常用来定义接口。

假如需要将抽象类实例化,需要定义一个factory constructor

抽象类通常会包含一些抽象的方法。
下面是包含抽象方法的例子:

// This class is declared abstract and thus
// can't be instantiated.
abstract class AbstractContainer {
  // ...Define constructors, fields, methods...

  void updateChildren(); // Abstract method.
}

没有使用abstract 关键字的类,即使包含抽象方法,也可以被实例化。

class SpecializedContainer extends AbstractContainer {
  // ...Define more constructors, fields, methods...

  void updateChildren() {
    // ...Implement updateChildren()...
  }

  // Abstract method causes a warning but
  // doesn't prevent instantiation.
  void doSomething();
}

隐式的接口(Implicit interfaces)

每一个类都隐式的定义一个接口,这个接口包含了这个类的所有实例成员和它实现的所以接口。

如果相应创建一个类A, 这个类A 支持类B 提供的API函数,但是不继承B 的实现,则类A 需要继承类B 的接口。

继承的例子如下:

// A person. The implicit interface contains greet().
class Person {
  // In the interface, but visible only in this library.
  final _name;

  // Not in the interface, since this is a constructor.
  Person(this._name);

  // In the interface.
  String greet(who) => 'Hello, $who. I am $_name.';
}

// An implementation of the Person interface.
class Imposter implements Person {
  // We have to define this, but we don't use it.
  final _name = "";

  String greet(who) => 'Hi $who. Do you know who I am?';
}

greetBob(Person person) => person.greet('bob');

main() {
  print(greetBob(new Person('kathy')));
  print(greetBob(new Imposter()));
}

上面代码对应的输出为:

Observatory listening on http://127.0.0.1:33001
Hello, bob. I am kathy.
Hi bob. Do you know who I am?

Process finished with exit code 0

扩展类(Extending a class)

使用extends 关键字来创建一个子类,super关键子来指定父类。

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

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

子类可以重载实例的方法,getters,setter。

可以使用override关键字来注释这个重载的方法。

枚举类型(Enumerated types)

枚举类型是一种特殊的类,通常用来表示相同类型的一组常量值。
每个枚举类型都用于一个index的getter,用来标记元素的元素位置。第一个枚举元素的标是0 。

enum Color {
  red,
  green,
  blue
}

assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);

获取枚举类中所有的值,使用value常数。

List<Color> colors = Color.values;
assert(colors[2] == Color.blue);

因为枚举类里面的每个元素都是相同类型,可以使用switch 语句来针对不同的值做不同的处理。

enum Color {
  red,
  green,
  blue
}
// ...
Color aColor = Color.blue;
switch (aColor) {
  case Color.red:
    print('Red as roses!');
    break;
  case Color.green:
    print('Green as grass!');
    break;
  default: // Without this, you see a WARNING.
    print(aColor);  // 'Color.blue'
}

枚举类型不能继承,实例化。

使用’mixins‘ 功能给类添加新的功能

mixins是一种方便重用一个类的代码的方法。
使用with 关键字来实现mixins的功能。

with用法的实例:

class Musician extends Performer with Musical {
  // ...
}

class Maestro extends Person
    with Musical, Aggressive, Demented {
  Maestro(String maestroName) {
    name = maestroName;
    canConduct = true;
  }
}

类变量和方法(Class variables and methods)

使用static关键字来使用类范围内的变量及方法

类常量

类常量的作用范围是类的内部。
类常量只有在被使用的时候才会被调用。

class Color {
  static const red =
      const Color('red'); // A constant static variable.
  final String name;      // An instance variable.
  const Color(this.name); // A constant constructor.
}

main() {
  assert(Color.red.name == 'red');
}

类方法

可以将类方法当做编译时的常量使用。

import 'dart:math';

class Point {
  num x;
  num y;
  Point(this.x, this.y);

  static num distanceBetween(Point a, Point b) {
    var dx = a.x - b.x;
    var dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
  }
}

main() {
  var a = new Point(2, 2);
  var b = new Point(4, 4);
  var distance = Point.distanceBetween(a, b);
  assert(distance < 2.9 && distance > 2.8);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容