本文共 8491 字,大约阅读时间需要 28 分钟。
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(Listarguments) { 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(Listarguments) { 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_cache = {}; 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 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创建附加属性,使用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(Listarguments) { 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(Listarguments) { 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(Listarguments) { 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 注释来避免警告
@proxyclass 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);
获得枚举值的列表,枚举的索引不变
Listcolore = Color.values;assert(colore[2] == Color.blue);
你可以在switch语句中使用枚举
enum Color { red, green, blue}main(Listarguments) { 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(Listarguments) { 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(Listarguments) { 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);}
您可以将静态方法作为编译时常量,例如,你可以将静态方法作为参数传递给一个常量的构造函数
转载地址:http://xvtwa.baihongyu.com/