方法是为对象提供行为的函数。java
实例方法能够访问实例变量和this
。下面的distanceTo()
就是一个实例方法的例子:git
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);
}
}
复制代码
Gettter 和 Setters 是为了可以读写对象属性的指定方法。回想一下,每一个实例变量都有一个隐式getter,还有可能有一个setter。 你可使用get
和set
关键字经过实现getter和setter来建立其余属性:github
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和setter,你能够从实例变量开始,稍后使用方法包装它们,而无需更改客户端代码。安全
注意:不管是否明肯定义了getter,增量(++)等运算符都以预期的方式工做。 为避免任何意外的反作用,运算符只需调用一次getter,将其值保存在临时变量中。ide
实例,getter和setter方法能够是抽象的,定义一个接口,但将其实现留给其余类。 抽象方法只能存在于抽象类中。(这个跟 java 里是同样的)函数
要使方法成为抽象,请使用分号(;)而不是方法体{}:post
abstract class Doer {
// 定义实例变量和方法...
void doSomething(); // 定义一个抽象方法.
}
class EffectiveDoer extends Doer {
void doSomething() {
// 提供一个实现,因此这里的方法不是抽象的...
}
}
复制代码
使用abstract
修饰符定义抽象类 - 没法实例化的类。 抽象类对于定义接口很是有用,一般还有一些实现。 若是但愿抽象类看起来是可实例化的,请定义工厂构造函数。ui
抽象类一般有抽象方法。 下面是一个声明具备抽象方法的抽象类:this
// 这个类定义了 abstract 不能被实例化
abstract class AbstractContainer {
// 定义构造函数,字段,方法...
void updateChildren(); // 抽象方法.
}
复制代码
每一个类都隐式定义一个接口,该接口包含该类的全部实例成员及其实现的任何接口。 若是要在不继承B实现的状况下建立支持B类API的A类,则A类应实现B接口。spa
类经过在implements
子句中声明它们而后提供接口所需的API来实现一个或多个接口。 例如:
// A 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 {...}
复制代码
用extends
去建立一个子类,用super
去指向一个超类
class Television {
void turnOn() {
_illuminateDisplay();
_activateIrSensor();
}
// ···
}
class SmartTelevision extends Television {
void turnOn() {
super.turnOn();
_bootNetworkInterface();
_initializeMemory();
_upgradeApps();
}
// ···
}
复制代码
子类能够覆盖实例方法,getter和setter。 你可使用@override
注释来覆盖成员:
class SmartTelevision extends Television {
@override
void turnOn() {...}
// ···
}
复制代码
要在类型安全的代码中缩小方法参数或实例变量的类型,可使用covariant关键字。
你能够覆盖下表中展现的运算符。 例如,若是定义Vector类,则能够定义一个+
方法来添加两个向量。
< |
+ |
| |
[] |
---|---|---|---|
> |
/ |
^ |
[]= |
<= |
~/ |
& |
~ |
>= |
* |
<< |
== |
- |
% |
>> |
注意:你可能已经注意到
!=
不是可覆盖的运算符。 表达式e1!= e2
只是!(e1==e2)
的语法糖。
这是一个覆盖+
和-
运算符的类示例:
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));
}
复制代码
若是覆盖==
,则还应该覆盖Object的hashCode
getter。(相似 java 中的覆写 equals(),还有 hashcode()) 有关重写==
和hashCode
的示例,请参阅实现映射键。
要在代码尝试使用不存在的方法或实例变量时检测或作出反应,你能够覆盖noSuchMethod()
:
class A {
// 除非你覆盖了 noSuchMethod,
// 用一个不存在的成员会致使 NoSuchMethodError 结果.
@override
void noSuchMethod(Invocation invocation) {
print('You tried to use a non-existent member: ' +
'${invocation.memberName}');
}
}
复制代码
除非知足如下条件之一,不然不能调用未实现的方法:
接收器具备静态类型dynamic
。
接收器有一个定义未实现方法的静态类型(抽象是ok的),接收器的动态类型有一个noSuchMethod()
实现,它与Object
类中的实现不一样。
有关更多信息,请参阅非正式noSuchMethod转发规范。
枚举类型(一般称为枚举或枚举)是一种特殊类,用于表示固定数量的常量值。
用enum
申明一个枚举类型
enum Color { red, green, blue }
复制代码
枚举中的每一个值都有一个index
getter,它返回枚举值的索引位置。 例如,第一个值具备索引0,第二个值具备索引1。
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);
复制代码
你能够在switch语句中使用枚举,若是不处理全部枚举值,将收到警告:
var aColor = Color.blue;
switch (aColor) {
case Color.red:
print('Red as roses!');
break;
case Color.green:
print('Green as grass!');
break;
default: // 不写这个 default,你会看到WARNING.
print(aColor); // 'Color.blue'
}
复制代码
枚举类型具备如下限制:
混合是一种在多个类层次结构中重用类代码的方法。
使用混合的方法是with
关键字后跟一个或多个mixin命名的类。 如下示例显示了两个使用mixins的类:
class Musician extends Performer with Musical {
// ···
}
class Maestro extends Person with Musical, Aggressive, Demented {
Maestro(String maestroName) {
name = maestroName;
canConduct = true;
}
}
复制代码
要定义一个mixin,首先建立一个mixin
开头的Object扩展类,而且不能声明构造函数。 除非你但愿mixin可用做常规类,不然请使用mixin
关键字而不是class
。 例如:
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');
}
}
}
复制代码
要指定只有某些类型可使用mixin - 例如,mixin能够调用它没有定义的方法 - 使用on
来指定所需的超类:
mixin MusicalPerformer on Musician {
// ···
}
复制代码
版本说明:Dart 2.1中引入了对mixin关键字的支持。 早期版本中的代码一般使用抽象类。 有关2.1 mixin更改的更多信息,请参阅Dart SDK changelog和2.1 mixin规范。
使用static
关键字实现类范围的变量和方法。
静态变量(类变量)一般用做类范围的状态和常量:
class Queue {
static const initialCapacity = 16;
// ···
}
void main() {
assert(Queue.initialCapacity == 16);
}
复制代码
静态变量在使用以前不会初始化。
注意:优先选择
lowerCamelCase
做为常量名称。
静态方法(类方法)不对实例进行操做,所以没法使用this
关键字。 例如:
import 'dart:math';
class Point {
num x, 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);
}
}
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);
}
复制代码
注意:对于经常使用或普遍使用的实用程序和功能,请考虑使用顶级(top-level)函数而不是静态方法。
你可使用静态方法做为编译时常量。 例如,能够将静态方法做为参数传递给常量构造函数。