1,Dart中的静态成员和静态方法
定义一个类的时候,默认的属性和方法都是非静态的(即实例的):
class Person{
//实例成员
String name;
int age;
//实例方法
printInfo(){
print('${this.name}---${this.age}');
}
}
实例成员和实例方法都必须通过类的实例对象去调用:
void main(){
Person person = new Person();//新建一个类的实例对象
person.printInfo();
}
可以通过static关键字来定义静态的属性和方法:
class Person{
//实例成员
String name;
int age;
//静态成员
static String sex;
//实例方法
printInfo(){
print('${this.name}---${this.age}');
}
//静态方法
static void staticPrintInfo(){
}
}
在类外部访问静态成员的时候,都是通过类来访问,而不需要将类实例化:
void main(){
//访问实例属性和实例方法
Person person = new Person();//新建一个类的实例对象
person.printInfo();
//访问静态属性和静态方法
print(Person.sex);
Person.staticPrintInfo();
}
在类的内部,静态方法里面只能访问静态成员,实例方法里面可以访问任何成员:
class Person{
//实例属性
String name;
int age;
//静态属性
static String sex;
//实例方法里面可以访问任何成员
printInfo(){
print('${this.name}---${this.age}');//实例方法中访问实例属性
print(sex);//实例方法中访问静态属性
staticPrintInfo();//实例方法中访问静态方法
}
//静态方法里面只能访问静态成员
static void staticPrintInfo(){
print('staticPrintInfo---$sex');//静态方法中访问静态属性
}
}
我们不可以在类的外部通过类的实例直接调用类的静态成员,但是可以通过实例方法来隐式调用类的静态成员,因为在类的内部,实例方法是可以调用任何成员的。
类的静态成员存在于类的定义体中,类的实例成员存在于类的实例中。
2,Dart中的对象操作符
在dart中,如果声明一个实例对象后没有进行初始化,那么调用该对象的属性或者方法就会报错:
Person person;
print(person.name);
报错如下:
Unhandled exception:
NoSuchMethodError: The getter 'name' was called on null.
Receiver: null
此时就使用到条件运算符?
Person person;
print(person?.name);
这时就运行正常了。person?的意思是,如果对象person为空,那么就不会调用属性name;如果对象person为非空,那么就调用属性name。
is操作符用于判断对象是不是某个类或者某类的子类的对象。
Person person = new Person('liwei', 12);
print(person is Person);
print(person is Object);
print(person is String);
打印结果如下:
true
true
false
as操作符用于强转类型:
var person;
person = '';
person = new Person('liwei', 12);
(person as Person).printInfo();//转换类型
..连缀操作符用于级联操作:
var person = new Person('张三', 12);
person.printInfo();
person.name = "李四";
person.age = 22;
person.printInfo();
这段代码也可以使用级联操作符简化:
var person = new Person('张三', 12);
person..printInfo()
..name = '王五'
..age = 22
..printInfo();
其结果是一样的。
3,继承相关。
下面是Person类的定义:
class Person{
String name;
num age;
Person(this.name, this.age);
printInfo(){
print('${this.name}, ${this.age}');
}
}
接下来我创建一个Person的子类IronMan:
class IronMan extends Person{
IronMan(String name, num age) : super(name, age);
}
可以看到,我们是通过extends关键字来继承的。子类可以继承父类的共有属性和方法,但是不能继承父类的构造函数。
如果父类中实现了默认的构造函数,那么我们需要在子类中也实现构造函数来给父类的构造函数传值。如上面代码所示,子类中有下面一行代码:
IronMan(String name, num age) : super(name, age);
其中IronMan(String name, num age)是子类的构造函数,通过子类的构造函数,将参数值传给父类的构造函数super(name, age)。
在子类中也可以扩展定义自己特有的属性和方法,如下:
class IronMan extends Person{
//在子类中定义自己的属性和方法
String sex;
//实现子类的构造函数,并且将参数值传给父类的构造函数
IronMan(String sex, num age, String name) : super(name, age){
this.sex = sex;
}
printIronManInfo(){
print('${this.name}, ${this.age}, ${this.sex}');
}
}
也可以在子类中覆写父类的方法:
class IronMan extends Person{
String sex;
IronMan(String sex, num age, String name) : super(name, age){
this.sex = sex;
}
//覆写父类的方法
@override
printInfo() {
print('${this.name}, ${this.age}, ${this.sex}');
}
}
4,抽象类
不管是在Objective-C中还是在Dart中,都有抽象类的概念。抽象类主要用于定义标准,不可使用抽象类直接生成实例,只有继承自抽象类的子类才可以实例化对象。
使用abstract关键字来定义抽象类:
//使用abstract关键字来定义抽象类
abstract class Animal{
}
如果我们要在抽象类中定义一个方法,要求该抽象类的子类必须实现该方法,那么可以将该方法定义成抽象方法:
//使用abstract关键字来定义抽象类
abstract class Animal{
//定义抽象方法(移除大括号的部分就是抽象方法了)
printInfo();
}
class Cat extends Animal{
@override
//抽象类的子类中,必须要实现抽象类中的抽象方法,不然会报错。
printInfo() {
print('info');
}
}
在抽象类中的定义的抽象方法,在抽象类的子类中必须实现,不然会报错。
当然了,在抽象类中也是可以定义非抽象方法的,但是在普通类中不可以定义抽象方法。
5,多态。
多态,顾名思义,多种状态。大白话说,多态就是父类定义一个方法不去实现,让继承它的子类去实现,每个子类会有不同的表现。
6,接口。
在Objective-C中,我们可以通过@interface关键字来定义接口。但是在Dart中,是没有interface关键字来定义接口的,dart里的普通类或者抽象类都可以作为接口被实现。
Dart中的接口是比较奇怪的,属性倒还好,直接声明就OK了;但是对于方法就有点奇怪了,因为dart中的普通类定义里的方法是需要实现的,比如下面这样:
class Animal{
//属性
String name;
//函数
void printInfo(){
}
}
当然,上面演示的是普通类的接口。下面来看一下抽象类的接口:
//抽象类
abstract class Animal{
//属性
String name;
//抽象函数
void printInfo();
}
通过比较我们发现,抽象类中是可以定义抽象函数的,该抽象函数在定义的时候不需要实现。所以,我们一般在Dart中通过抽象类来定义接口。
如下是一个抽象类,里面定义了一个属性和一个抽象方法这两个接口:
//抽象类
abstract class Animal{
//属性
String name;
//抽象函数
void printInfo();
}
然后我在该抽象类的子类中对该接口进行实现:
class Cat implements Animal{
@override
String name;
@override
void printInfo() {
print('Cat');
}
}
class Dog implements Animal{
@override
String name;
@override
void printInfo() {
}
}
需要注意的是,使用 implements 关键字来对抽象类中的接口进行实现。抽象类中定义的接口,在子类中实现的时候都需要实现。
7,extends和implements的区别
extents用于继承,implements用于实现接口。
看到这里,我们可能还是迷迷糊糊,这两者到底有啥区别呢?接下来可能会让你豁然开朗。
首先,我定义了两个抽象类:
abstract class Animal{
String name;
printInfo();
}
abstract class People{
String nation;
singASong();
}
我们知道,Dart中的类也是单继承的,比如下面这种写法就肯定会报错:
class Thing extends Animal,People{
}
但是我现在将上面的extends换成implements,也就是说,Animal,People相对于Thing这个类不是父类的存在,而是接口封装的存在,那么程序就不会有任何问题。
想必看到这里你应该弄清楚接口的概念了吧。
dart中的抽象类,既可以作为一个父类去生成对应的子类,也可以作为其他类的接口封装。
在Dart中,我们使用implements关键字来实现使用抽象类来封装的接口,并且一个类可以实现多个接口,如下:
//封装接口的抽象类
abstract class Animal{
String name;
printInfo();
}
//封装接口的抽象类
abstract class People{
String nation;
singASong();
}
//一个类可以实现多个接口
class Thing implements Animal,People{
@override
String name;
@override
String nation;
@override
printInfo() {
return null;
}
@override
singASong() {
return null;
}
}
8,mixins(混入)
mixins的中文意思是混入,也就是在类中混入其他功能。mixins特性是Dart中特有的特性,可以用来实现类似多继承的功能。
下面我定义了三个不同的类:
class A{
printA(){
print('A');
}
}
class B{
printB(){
print('B');
}
}
class C{
printC(){
print('C');
}
}
然后我们使用Dart的mixins特性来创建一个类D:
class D with A,B,C {
}
然后我们新建一个D类的实例来验证一下,该实例是否具有类A、B、C的功能:
main(){
D d = new D();
d.printA();
d.printB();
d.printC();
}
打印结果如下:
A
B
C
这说明类D的实例具有了类A、B、C的功能。
需要注意的是,作为mixins的类只能继承自Object,而不能继承自其他的类。也就是说,上例中的 A,B,C 都必须是继承自Object,否则就会报错。比如下面的例子:
class A{
printA(){
print('A');
}
}
class B extends A{
printB(){
print('B');
}
}
class C {
printC(){
print('C');
}
}
class D with B,C {
}
C默认继承自Object,这是没有问题的。但是B继承自A,程序会报错如下:
The class 'B' can't be used as a mixin because it extends
a class other than Object.
另外一点需要注意的是,作为mixins的类不能有构造函数。比如下面这个类就不能作为mixins的类:
class A{
A(){
//这里是类A的构造函数
}
printA(){
print('A');
}
}
当A作为mixins的类的时候就会报错:
继承与mixins也可以同时使用:
class A{
A(){
//这里是类A的构造函数
}
printA(){
print('A');
}
}
class B {
printB(){
print('B');
}
}
class C {
printC(){
print('C');
}
}
//D继承自A,并且混入B和C的功能
class D extends A with B,C{
}
我们知道,可以通过 is 关键字来判断对象的类型。那么大家看一下下面这个例子,猜猜生成的实例d是什么类型:
class A{
A(){
//这里是类A的构造函数
}
printA(){
print('A');
}
}
class B {
printB(){
print('B');
}
}
class C {
printC(){
print('C');
}
}
//D继承自A,并且混入B和C的功能
class D extends A with B,C{
}
main(){
D d = new D();
print(d is A);
print(d is B);
print(d is C);
print(d is D);
}
打印结果如下:
true
true
true
true
可以看到,实例对象d既是A类型,也是B类型,也是C类型,也是D类型。D继承自A,所以 d is D 和 d is A 都返回 true 这很容易理解,但是其他两个也返回 true 就很难理解了是吧?这其实是Dart语言的特性。我们可以将mixins理解成多继承(但是实际并不是多继承),这样就可以将B和C理解成D的超类,这样 d is B 和 d is C 也返回 true 就很容易理解了。
以上。