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