类:
Dart 是支持基于 mixin 继承机制的面向对象语言,所有对象都是一个类的实例,而除了 Null 以外的所有的类都继承自 Object 类
使用类的成员
对象的 成员 由函数和数据(即 方法 和 实例变量)组成。方法的 调用 要通过对象来完成,这种方式可以访问对象的函数和数据。
使用 . 来访问对象的实例变量或方法
class Person {
String? name;
String? age;
void getName() {}
}
main() {
var person = Person();
person.name; //使用(.)来访问对象的实例变量
person.getName(); //使用(.)来访问对象的方法
}
使用 ?. 代替(?左边如果为空返回 null,否则返回右边的值). 可以避免因为左边表达式为 null 而导致的问题:
构造函数的声明:
class Person {
String? name; //?左边如果为空返回 null,否则返回右边的值。
int? age;
String? sex;
//默认构造函数
// 如果你没有声明构造函数,那么 Dart 会自动生成一个无参数的构造函数并且该构造函数会调用其父类的无参数构造方法。
// Person(); //子类不会继承父类的构造函数,如果子类没有声明构造函数,那么只会有一个默认无参数的构造函数。
// class Sons extends Person {
// Sons(String name, int age, String sex) : super();
// }
//声明一个与类名一样的函数即可声明一个构造函数,构造函数是不能被继承的,这将意味着子类不能继承父类的命名式构造函数
Person(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
//Dart 则提供了一种特殊的语法糖来简化该步骤:
//Person(this.name, this.age, this.sex);
//可以为一个类声明多个命名式构造函数来表达更明确的意图:
Person.A(this.name, this.age, this.sex);
Person.B(this.name, this.age);
Person.C(this.name);
Person.D()
: name = "jack",
age = 18,
sex = "boy"; //除了调用父类构造函数之外,还可以在构造函数体执行之前初始化实例变量。每个实例变量之间使用逗号分隔。初始化列表
@override
String toString() {
// TODO: implement toString
return "name=$name,age=$age,sex=$sex";
}
}
使用构造函数
可以使用 构造函数 来创建一个对象。构造函数的命名方式可以为 类名 或 类名 . 标识符 的形式
main(){
var person1 = Person("jack", 18, "boy");
var person2 = Person.A("jack", 18, "boy
}
常量构造函数
class Point {
//成员变量都是final类型,且构造函数用const修饰
final int x; //不能赋初始值 final int x=0;
final int y;
const Point(this.x, this.y);
void getAdd() {
print(x + y);
}
}
main(){
//两个使用相同构造函数相同参数值构造的编译时常量是同一个对象:
var point = const Point(2, 1);
var point2 = const Point(2, 1);
print(identical(point, point2))//true
//如果实例化时不加const修饰符,即使调用的是常量构造函数,实例化的对象也不是常量实例
var point = const Point(2, 1);
var point2 = Point(2, 1);
print(identical(point, point2));//false
}
使用 extends 关键字来创建一个子类,并可使用 super 关键字引用一个父类:
//如果父类没有声明任何一个构造函数,则子类会调用默认的无参构造函数 super()
class Dad {}
class Sons extends Dad {
String name;
Sons(this.name);
// Sons(this.name) : super();
}
如果父类没有匿名无参数构造函数,那么子类必须调用父类的其中一个构造函数,为子类的构造函数指定一个父类的构造函数只需在构造函数体前使用(:)指定,并且要传入父类所有构造函数里的参数。如下Son1(String name)必须传入参数name;
class Dad1 {
String name;
Dad1(this.name);
}
class Son1 extends Dad1{
Son1(String name) : super(name);
}
子类覆盖父类的方法
class Dad2 {
void dadFun() {
print("父类的方法");
}
}
class Son2 extends Dad2 {
void sonFun() {
print("子类自己的方法");
}
//重写父类的方法
@override
void dadFun() {
// TODO: implement dadFun
super.dadFun(); //调用父类的方法 打印输出:父类的方法
print("子类覆盖父类的方法"); //注释掉上行代码 super.dadFun();会覆盖父类的该方法实现
}
}
//使用关键字 abstract 标识类可以让该类成为 抽象类,抽象类将无法被实例化。抽象类常用于声明接口方法、有时也会有具体的方法实现
abstract class AbstractDemo {
void getNum();
void getPei() {
print("抽象父类具体实现方法");
}
}
class Demo1 extends AbstractDemo {
@override
void getNum() {
print("实现抽象类的具体内容");
}
@override
void getPei() {
// TODO: implement getPei
super.getPei();//调用父类的方法 打印输出:父类的方法
print("子类具体实现方法");//注释掉上行代码 super.getPei();会覆盖父类的该方法实现
}
}
//一个类可以通过关键字 implements 来实现一个或多个接口并实现每个接口定义的 API
//类和接口是统一的,类就是接口
class Ainterface1 {
void run() {}
}
class Ainterface2 {
void walk() {}
}
class Demo2 implements Ainterface1, Ainterface2 {
@override
void run() {
// TODO: implement run
}
@override
void walk() {
// TODO: implement walk
}
}
类变量和方法
使用关键字 static
可以声明类变量或类方法。
和java的一样,省略了
mixin
类似java中的接口,但是区别java的接口是有具体的实现。也可以类似java中的class ,定义变量和方法,可以参考深入理解 Dart 中的 Mixin
一、作为mixins的类只能继承object,不能继承其他类
class C {}
class A extends C {}
class B with A {}//此处会提示错误:The class 'A' can't be used as a mixin because it extends a class other than 'Object'
二、作为mixin的类不能有构造函数
class C {}
class A {
String name;
A(this.name);
}
//提示错误:The class 'A' can't be used as a mixin because it declares a constructor
class B1 with A {}
//正常
class B2 with C {}
三、一个类可以有多个有个mixins,访问到类里的变量和方法
class C {
String c = "C";
void printC() {
print("C");
}
}
class A {
String a = "a";
void printA() {
print("A");
}
}
class B with A, C {
@override
void printC() {
super.printC();
}
@override
void printA() {
super.printA();
}
void printB() {
print("a=$a,c=$c");
}
}
B with A 和C ,能在B里访问A和C里面的方法printA()和print()方法以及变量a和c;
四、声明mixin的顺序,代表类似继承的优先级,越后面越高级,后面的属性方法会覆盖前面的属性
class C {
void run() {
print("c run");
}
}
class A {
void run() {
print("a run");
}
}
class B with C, A {}
main() {
var b = B();
b.run();
}
输出结果//a run
class A 和class C 里面都有run()方法,但B类先withC 再跟上A,所以A的方法会覆盖前面C的同名方法,如果换成
class B with A, C {}
输出结果则会打印:c run
另外如果B类继承一个类,比如D类,D类里面又有run()方法,看下结果
class D {
void run() {
print("d run");
}
}
class C {
void run() {
print("c run");
}
}
class A {
void run() {
print("a run");
}
}
class B extends D with A, C {}
main() {
var b = B();
b.run();
}
//输出打印结果;c run
结果是c run 说明对于继承的类来说优先级也是一样的
想要实现一个 Mixin,请创建一个继承自 Object 且未声明构造函数的类。除非你想让该类与普通的类一样可以被正常地使用,否则请使用关键字 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');
}
}
}
可以用关键字on来指定哪些类可以使用该类Mixin类,使用on关键字可以指定mixin的父类
mixin A on C{}
class C{}
class D{}
class B extends C with A{}
class B extends D with A{}//编译器报错 ‘A'无法mixed on 'D'
mixin类A指定mixin的父类为C,所以只有继承了C类才能with A类,B继承了C,所以可以访问mixin A ,但D没有,所以编译器会提示错误。