0 说明
该系列教程主要是为有一定语言基础 C/C++的程序员,快速学习一门新语言所采用的方法,属于在C/C++基础上扩展新语言的模式。
1 面向对象基础知识
说明:这里主要是基于C++面向对象着门语言,分析与其不同的部分,属于扩展式的学习模式。Dart语言本身也是面向对象的程序语言,
编码习惯说明:类的首字母要大写,方法首字母小写。
1.1 类的属性信息获取
在dart语言中,属性的获取一般可以用$符号直接获取,这里以Person类为例,具体描述如下:
class Person {String name = 'wang';int age = 30;Person() {}void printInfo() {print("printInfo:");print("use \$ label");print("$name----$age");print("use this pointer");print("${this.name}----${this.age}");}
}void main() {Person p = new Person();p.printInfo();print("Person's property:");print("name=${p.name},age=${p.age}");
}
命令执行后效果如下:
Connecting to VM Service at ws://127.0.0.1:63468/DKkz_f3A8aw=/ws
printInfo:
use $ label
wang----30
use this pointer
wang----30
Person's property:
name=wang,age=30
1.2 默认构造函数和命名构造函数
Dart中构造函数和C++中有所不同,并不是直接编写的构造函数有多个,而是一个默认构造函数和多个不同的命名构造函数,都可以用于对象的实例化,这里以Person类为例来解读默认构造函数和命名构造函数的差别,代码如下所示:
class Person {String name = 'wang';int age = 30;//1 默认构造函数,当实例化一个对象时,会自动调用到该函数//一般编码模式:// Person(String name, int age) {// this.name = name;// this.age = age;// }//Dart语言中的简写模式,功能同上 注释:Person(this.name, this.age);//2 命名构造函数系列Person.now() {print("命名构造函数now");}Person.init(String name) {this.name = name;print("命名构造函数init:$name");}void printInfo() {print("$name---$age");}
}void main() {Person p1 = new Person("wang", 30);Person p2 = new Person.now();Person p3 = new Person.init("li");p1.printInfo();p2.printInfo();p3.printInfo();
}
命令执行后效果如下:
Connecting to VM Service at ws://127.0.0.1:63783/veW3pzv-NKs=/ws
命名构造函数now
命名构造函数init:li
wang---30
wang---30
li---30
1.3 私有(private)属性和公有(public)属性
这里的private变量一般使“ _ ”开头,而非“_”开头的变量一般都是public变量。代码如下所示:
class Person {//public属性String name = 'wang';//private属性//注意:必须在Person独立出的类文件中,才可以使private属性生效,否则无效int _age = 30;Person(this.name, this._age);void printInfo() {print("$name---$_age");}
}void main() {Person p1 = new Person("wang", 30);p1._age = 30;p1.printInfo();
}
但要非常注意:直接在该文件中使用时private属性并不生效,即外界依然可以访问。只有在独立类文件Person中时才会生效。命令执行后效果如下:
Connecting to VM Service at ws://127.0.0.1:64385/Oid5LlpsVOg=/ws
wang---30
1.4 get和set 计算属性
get和set的使用,代码如下所示:
class Circle {double radius;Circle(this.radius);//getter实现// double s() {// return radius * radius * 3.14;// }//{等价于上面的方法实现}//setter实现set setRadius(double radius) {this.radius = radius;}
}void main() {Circle c = new Circle(5.0);c.setRadius = 7.0;//setter的使用print("r=${c.radius},s=${c.s}");//getter的使用
}
命令执行后效果如下:
Connecting to VM Service at ws://127.0.0.1:64936/um9Y1LlW7Zc=/ws
r=7.0,s=153.86
1.5 初始化操作
构建对象前的初始化变量操作,在构造函数运行前赋值,代码如下所示:
class Circle {double radius;//变量初始化操作。在构造函数运行前赋值Circle() : radius = 3.0 {print("r=${radius}");}get s {return this.radius * this.radius * 3.14;}
}void main() {Circle c = new Circle();print("r=${c.radius},s=${c.s}");
}
命令执行后效果如下:
Connecting to VM Service at ws://127.0.0.1:65060/-cx0Vbd4POI=/ws
r=3.0
r=3.0,s=28.26
1.6 静态属性和静态方法
在Dart语言中一般使用static关键字来实现对变量和方法的描述。规则如下:
- 静态方法中不能使用非静态方法和属性。
- 非静态方法中可以使用静态方法和静态属性。
1.7 级联操作..
代码实现如下:
class Person {String name = 'wang';int age = 30;Person(this.name, this.age);void printInfo() {print("$name---$age");}
}void main() {Person p1 = new Person("wang", 30);//级联操作赋值p1..name = "wang-5"..age = 40..printInfo();
}
命令执行后效果如下:
Connecting to VM Service at ws://127.0.0.1:50341/2a365aWm2oY=/ws
wang-5---40
常量构造函数
2 面向对象(继承、封装、多态)
2.1 抽象类和抽象方法
这里的描述主要针对相比C++语言的抽象类中不同之处,做对比学习,如下:
- 抽象类主要用于定义标准。使用abstract关键字,抽象类中的抽象方法则无需再使用abstract关键字来声明。
- 抽象类中如果只声明方法但不实现则是抽象方法,即没有方法体的方法就是抽象方法了。如果实现了的方法就是普通方法,即有方法体的方法。
抽象类及对应方法 代码实现如下:
//抽象类
abstract class Animal {//抽象类中的抽象方法void eat();void run();//抽象类中的一般方法void printInfo() {print("class Animal info");}
}
2.2 implements接口
Dart中没有关键字来定义接口的关键字,普通类和抽象类都可以作为接口被实现,使用关键字implements关键字进行实现。如果实现的类是普通类,需要将普通类和抽象中的属性和方法全重写。抽象类可以定义抽象方法,普通类不可以,所以一般如果要实现接口的方式,使用抽象类定义接口。这里要注意extends和implemnets的区别:在Dart语言中,继承抽象类 和实现抽象类是不同的,继承只会重写抽象类里的抽象方法,而实现会重写抽象类里的所有变量和方法。相关代码如下所示:
//复用上一段代码的Animal。。。//继承:只需要重写抽象类中的抽象方法
class Cat extends Animal {@overridevoid eat() {// TODO: implement eat}@overridevoid run() {// TODO: implement run}
}
//实现需要重写抽象类中的所有属性和方法
class Dog implements Animal {@overridelate String name;@overridevoid eat() {// TODO: implement eat}@overridevoid printInfo() {// TODO: implement printInfo}@overridevoid run() {// TODO: implement run}}
说明:如果是implements实现多个抽象类,则需要重写多个抽象类里的所有变量和方法。
2.3 mixins功能
主要用于实现类似多继承的功能。mixins的使用条件随着Dart的版本不断更新而有所改,mixins 3.X版本中约束条件如下:
- 作为mixins的类只能继承自Object,不能继承其他类
- 作为mixins的类不能有构造函数
- 一个类可以mixins多个mixins类
- mixins不是继承,也不是接口,而是一种全新的特性
代码实现如下所示:
mixin A {//作为minxins类,只能继承自ObjectprintA() {print("This is A");}run() {print("run A");}
}mixin B {//作为minxins类,只能继承自ObjectprintB() {print("This is B");}run() {print("run B");}
}//C混合了A类和B类,类似继承,C的实例化类可以使用A类以及B类中的方法
class C with A, B {}main() {C c = new C();c.printA();c.printB();c.run();
}
命令执行后效果如下:
Connecting to VM Service at ws://127.0.0.1:55350/kWXd6C3DRl4=/ws
This is A
This is B
run B
注意:如果有相同方法,则执行时主要依赖with的顺序。
同时这里也可以同时extends其他类基础上再使用mixins机制。关键代码如下所示:
class C extends X with A, B {}
2.4 late关键字
表示延迟初始化,不在对象初始化时初始化,而是在对象初始化之后。参考2.2 implements接口中demo。
2.5 identical函数
主要用于检查两个引用是否指向同一个对象。关于identicial的判定,参考如下代码:
void main() {var o1 = new Object();var o2 = new Object();var isIdentical = identical(o1, o2); // false, diff objects.isIdentical = identical(o1, o1); // true, same objectisIdentical =identical(const Object(), const Object()); // true, const canonicalizesisIdentical = identical([10], [10]); // falseisIdentical = identical(const [10], const [10]); // trueisIdentical = identical(const [1], const [2]); // false
}
2.6 常量构造函数
在Dart语言中,const一方面是内存开销减少,另一方面源自从常量组件是不应该改变的需求。常量构造函数需要满足以下约束:
- 常量构造函数需要以const关键字修饰;
- const构造函数必须用于成员变量都是final的类;
- 如果实例化不加const修饰符,即使调用的是常量构造函数,实例化的对象也不是常量实例对象;
- 实例化常量的构造函数的时候,多个地方创建这个对象,如果传入的值相同,只会保留一个对象;
这里给出一个demo,代码如下所示:
class Rect {final int width;final int height;const Rect({required this.width, required this.height});
}
3 泛型
和C++基本一致,主要解决代码中数据类型的复用问题。一般都是泛型方法和泛型类中使用。