Dart基础-类

dart是面向对象的编程语言,每一个对象是一个类的实例,所有类都源于Object,创建一个对象,你可以使用 new 关键字构建一个类,构造函数的名字可以是 ClassName 或 ClassName.identifier

var jsonData = JSON.decode('{"x":1,"y":2}');
var p1 = new Point(2, 2);
var p2 = new Point.fromJson(jsonData);

对象里有成员函数和数据,包括方法和实例变量,使用 . 可以引用一个实例变量或方法

var p = new Point(2, 2);
//设置实例变量y的值
p.y = 3;
assert(p.y == 3);
//调用distanceTo()方法
num distance = p.distanceTo(new Point(4, 4));

使用级联操作符 .. 对一个对象成员做一系统操作

//获取一个对象
querySelector('#button')
  //使用它的成员
  ..text = 'Confirm'
  ..classer.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'));

一些类提供常量的构造函数,创建编译时常量的构造函数时,使用 const 而不是 new

var p = const ImmutablePoint(2, 2);

构建两个相同的的编译时常量

var a = const ImmutablePoint(1, 1);
var b = const ImmutablePoint(1, 1);
//他们是相同的实例
assert(identical(a, b));

实例变量

声明实例变量,所有未初始化的实例变量的值为null

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

所有实例变量都有隐式的getter方法,不是常量的实例变量都有隐式的setter方法

class Point {
  num x;
  num y;
}

main(List<String> arguments) {
  var point = new Point();
  //使用x的setter方法
  point.x = 4;
  //使用x的getter方法
  assert(point.x == 4);
  //默认值为空
  assert(point.y == null);
}

构造函数

声明一个构造函数就是创建一个与类同名的函数,关键字 this 是指当前的,只有在命名冲突时有效,否则dart会忽略处理

class Point {
  num x;
  num y;

  Point(num x, num y) {
    this.x = x;
    this.y = y;
  }
}

通常一个实例变量分配一个构造函数参数,这样使语法理简单

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 Person {
  Person.fromJson(Map data) {
    print('in Person');
  }
}

class Employee extends Person {
  Employee.fromJson(Map data) : super.fromJson(data) {
    print('in Employee');
  }

}

main(List<String> arguments) {
  var emp = new Employee.fromJson({});
}

因为父类的构造函数的参数是执行之前调用的,所以一个参数可以是一个表达式

Employee() : super.fromJson(findDefaultData());

初始化列表

除了调用父类的构造函数,你也可以在构造函数体运行之前初始化实例变量

class Point { num x; num y; Point(this.x, this.y); Point.fromJson(Map jsonMap) : x = jsonMap['x'], y = jsonMap['y'] { print('In Point.fromJson(): ($x, $y)'); } }

重定向构造函数

有时一个构造函数的唯一目的是重定向到同类的另一个构造函数

class Point {
  num x;
  num y;

  Point(this.x, this.y);

  Point.alongXAxis(num x) : this(x, 0);
}

常量构造函数

如果一个类生成的对象永远不会改变,你可以让这些对象变成编译时常量,为此定义一个 const 构造函数并确保所有实例变量是 final 的

class ImmutablePoint {
  final num x;
  final num y;
  const ImmutablePoint(this.x, this.y);
  static final ImmutablePoint origin = const ImmutablePoint(0, 0);
}

工厂构造函数

使用 factory 关键字实现构造函数时,不一定要创建一个类的新实例,例如,一个工厂的构造函数可能从缓存中返回一个实例,或者返回一个子类的实例

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

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

main(List<String> arguments) {
  var logger = new Logger('UI');
  logger.log('Button clicked');
}

方法

方法就是函数,提供了对象的行为

实例方法

实例对象可以访问实例变量和方法

import 'dart:math';

class Point {
  num x;
  num 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

getter和setter是特殊的方法,可以读写访问一个对象的属性,每个实例变量都有一个隐式的getter,如果适当的加上一个setter,您可以通过实现getter和setter创建附加属性,使用get和set关键词

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

main(List<String> arguments) {
  var rect = new Rectangle(3, 4, 20, 15);
  assert(rect.left == 3);
  rect.right = 12;
  assert(rect.left == -8);
}

抽象方法

实例、getter和setter方法可以是抽象的,抽象方法使用分号 ; 而不是方法体

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

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

class EffectiveDoer extends Doer {
  void doSomething() {
    //...实现一个抽象方法...
  }
}

重写运算符

您可以覆盖如下所示的运算符

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

下面是重写 + 和 - 的例子

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

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

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

main(List<String> arguments) {
  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);
}

抽象类

使用abstract修饰符定义的抽象类不能被实例化,抽象类用于定义接口,常用于实现,如果你想让抽象类可实例化,定义工厂构造函数

抽象类里通常有抽象方法

abstract class AbstractContainer {
  //...定义构造函数,字段、方法...

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

下面的类并不是抽象类,因此可以被实例化,尽管它定义了一个抽象方法

class SpecializedContainer extends AbstractContainer {
  //...定义更多的构造方法、字段、方法...

  void updateChildren() {
    //...实现updateChildren()...
  }

  void doSomething();
}

隐式接口

每个类都隐式定义一个接口,包含所有类和实例成员

通过声明一个类实现一个或多个接口的implements子句,然后提供所需的api接口

class Person {
  final _name;
  Person(this._name);
  String greet(who) => 'Hello, $who. I am $_name.';
}

class Imposter implements Person {
  final name = "";
  String greet(who) => 'Hi $who. Do you know who I am?';
}

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

main(List<String> arguments) {
  print(greetBob(new Person('kathy')));
  print(greetBob(new Imposter()));
}

这是指定一个类实现多个接口的例子

class Point implements Comparable, Location {
  // ...
}

类的继承

使用 extends 创建一个子类,以及 super 引用父类

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

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

子类可以重写实例方法、getter和setter,下面的例子重写了noSuchMethod()方法

class A {
  void noSuchMethod(Invocation mirror) {
    print('You tried to use a non-existent member:${mirror.memberName}');
  }
}

您可以使用 @override 注释表明你是故意重写

class A {
  @override
  void noSuchMethod(Invocation mirror) {
    // ...
  }
}

如果你使用noSuchMethod()来实现每一个可能的getter、setter、类方法,你可以使用 @proxy 注释来避免警告

@proxy
class A {
  void noSuchMethod(Invocation mirror) {
    // ...
  }
}

枚举类型

枚举类型,通常被称为enumerations或enums,是一种特殊的类,用于表示一个固定数量的常量值,不能显式的实例化

声明一个枚举类型使用 enum 关键字

enum Color {
  red,
  green,
  blue
}

每个枚举的索引通过 index 获得,返回从零开始的位置值的枚举声明

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

获得枚举值的列表,枚举的索引不变

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

你可以在switch语句中使用枚举

enum Color {
  red,
  green,
  blue
}

main(List<String> arguments) {
  Color aColor = Color.blue;
  switch (aColor) {
    case Color.red:
      print('Red as Roses!');
      break;
    case Color.green:
      print('Green as grass!');
      break;
    default:
      print(aColor);
  }
}

向类添加新的功能:混入类

混入类重用一个类的代码在多个类层次结构,使用 with 关键字后面跟着一个或多个混入类的名字

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

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

要实现混入类,创建一个类、扩展对象,声明没有构造函数,没有父类调用

abstract class 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');
    }
  }
}

类的变量和方法

使用 static 关键字实现类的变量和方法

静态变量

静态变量(类变量)是类的常量

class Color {
  //不变的静态变量
  static const red = const Color('red');
  //实例变量
  final String name;
  //常量的构造函数
  const Color(this.name);
}

main(List<String> arguments) {
  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(List<String> arguments) {
  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);
}

您可以将静态方法作为编译时常量,例如,你可以将静态方法作为参数传递给一个常量的构造函数

你可能感兴趣的:(基础,Dart)