内部团队学习,以简单直接为主
概述
- Dart是一个面向对象的语言,面向对象中非常重要的概念就是
类
,类的实例就是对象
构造函数、类成员、方法以及枚举的定义
/** 代码输出结果如下
* 普通构造函数:name=name1,age=18,sex=null
* 命名构造函数:name=name2,age=28,sex=Gender.Girl
* 命名构造函数:name=name3,age=30,sex=Gender.Boy
* 初始化列表:name=name4,age=30,sex=null
* 构造函数重定向:name=name5,age=0,sex=null
* 常量构造函数:false
* 工厂构造函数:true
*/
main(List<String> args) {
// 普通构造函数
var p1 = Person("name1", 18);
print("普通构造函数:${p1.toString()}");
// 命名构造函数
var p2 = Person.withNameAgeSex("name2", 28, sex: Gender.Girl);
print("命名构造函数:${p2.toString()}");
// 命名构造函数
var p3 =
new Person.fromMap({'name': 'name3', 'age': 30, 'sex': Gender.Boy});
print("命名构造函数:${p3.toString()}");
// 初始化列表
var p4 = new Person.withNameAge('name4', 30);
print("初始化列表:${p4.toString()}");
// 构造函数重定向
var p5 = new Person.fromName('name5');
print("构造函数重定向:${p5.toString()}");
// 常量构造函数
var p6 = Person2('name6');
var p7 = Person2('name6');
print("常量构造函数:${identical(p6, p7)}");
// 工厂构造函数
final p8 = Person3.withName("name7");
final p9 = Person3.withName("name7");
print("工厂构造函数:${identical(p8, p9)}");
}
/** 枚举(通常用于表示固定数量的常量值)
* 枚举类型中有两个比较常见的属性:
* index: 用于表示每个枚举常量的索引, 从0开始.
* values: 包含每个枚举值的List.
*/
enum Gender { Boy, Girl }
// 类的定义
class Person {
// 成员变量
String name;
int age;
Gender sex;
String desc;
/** 构造函数
* 1、当类中没有明确指定构造方法时,将默认拥有一个无参的构造方法
* 2、当有了自己实现了构造函数时,默认的构造方法将会失效,不能再使用
* 3、Dart本身不支持函数的重载
* 4、构造函数的分类:
* (1)普通构造函数
* (2)命名构造函数
* (3)初始化列表
* (4)重定向构造函数
* (5)常量构造函数
* (6)工厂构造函数
*/
/**
* 普通构造函数
*/
// Person(String name, int age) {
// this.name = name;
// this.age = age;
// }
// 简化语法糖,等同于上面的构造函数
Person(this.name, this.age);
/** 命名构造函数
* 因为不支持方法(函数)的重载,所以我们没办法创建相同名称的构造方法
* 我们需要使用命名构造方法来满足这一需求
*/
// Person.withNameAgeSex(String name, int age, {Gender sex}) {
// this.name = name;
// this.age = age;
// this.sex = sex;
// }
// 简化语法糖,等同于上面的构造函数
Person.withNameAgeSex(this.name, this.age, {this.sex});
// 将一个Map转成对象,可以提供如下的构造方法
Person.fromMap(Map<String, Object> map) {
this.name = map['name'];
this.age = map['age'];
this.sex = map['sex'];
}
/** 初始化列表(类似C++语法)
* 在初始化列表里可以写一些逻辑表达式,这个要比参数给默认值更加灵活,参数给默认值必须是给一个明确的值
*/
Person.withNameAge(this.name, this.age, {String desc})
: desc = desc ?? (age > 30 ? '中年人' : '年轻人');
/** 构造函数重定向
* 在一个构造函数中,去调用另外一个构造函数(注意:是在冒号后面使用this调用)
*/
Person.fromName(String name) : this(name, 0);
// 方法重写
@override
String toString() {
return 'name=$name,age=$age,sex=$sex';
}
// 方法定义
eat() {
print('$name在吃东西');
}
/** setter和getter
* 默认情况下,Dart中类定义的属性是可以直接被外界访问的
* 但是某些情况下,我们希望监控这个类的属性被访问的过程,这个时候就可以使用setter和getter了
*/
String get getName {
return name;
}
set setName(String name) {
this.name = name;
}
}
class Person2 {
final String name;
/** 常量构造函数(一般只有一个)
* 在某些情况下,传入相同值时,我们希望返回同一个对象,这个时候,可以使用常量构造方法
* 使用identical(对象1, 对象2)函数来判断两个对象是否是同一个对象
*
* 注意一:拥有常量构造方法的类中,所有的成员变量必须是final修饰的.
* 注意二:为了可以通过常量构造方法,创建出相同的对象,不再使用 new 关键字,而是使用 const 关键字
* 如果是将结果赋值给const修饰的标识符时,const可以省略
*/
const Person2(this.name);
}
class Person3 {
String name;
int age;
static final Map<String, Person3> _nameCache = {};
/** 工厂构造函数
* Dart提供了factory关键字, 用于通过工厂去获取对象
*/
factory Person3.withName(String name) {
if (_nameCache.containsKey(name)) {
return _nameCache[name];
} else {
final p = Person3(name, age:28);
_nameCache[name] = p;
return p;
}
}
Person3(this.name, {this.age = 18});
}
抽象类、类的继承
- 一般来说抽象类
不能实例化
,但是有工厂构造函数
的抽象类是可以
被实例化的
- 抽象类中的
抽象方法必须被子类实现
, 抽象类中已经被实现的方法, 可以不用子类重写,但是可以被重写
- Dart中的继承使用
extends
关键字
- 子类中使用super来访问父类
- 父类中的所有成员变量和方法都会被继承,但是构造方法除外
main(List<String> args) {
Dog d = Dog(null, 5);
d.run();
}
/** 抽象类
* 抽象类不能实例化
* 抽象类中的抽象方法必须被子类实现, 抽象类中已经被实现的方法, 可以不用子类实现,但是可以被重写
*/
abstract class Animal {
int age;
Animal(this.age);
/** 抽象方法
* 抽象方法,必须存在于抽象类中。
* 抽象类是使用abstract声明的类。
*/
run();
}
/** 继承
* Dart中的继承使用extends关键字
* 子类中使用super来访问父类
* 父类中的所有成员变量和方法都会被继承,,但是构造方法除外
*/
class Dog extends Animal {
// 子类可以拥有自己的成员变量
String name;
/** 子类中可以调用父类的构造方法
* 子类的构造方法在执行前,将隐含调用父类的无参默认构造方法(没有参数且与类同名的构造方法)。
* 如果父类没有无参默认构造方法,则子类的构造方法必须在初始化列表中通过super【显式】调用父类的某个构造方法。
*/
Dog(String name, int age) : name = name ?? "旺财", super(age);
// 对父类的方法进行重写
@override
String toString() {
return "name=$name,age=$age";
}
// 实现父类中的抽象方法
@override
run() {
print('${name}在奔跑');
}
}
隐式接口
- Dart中没有哪一个关键字是来定义接口的
- 默认情况下所有的类都是隐式接口
- Dart只支持
单继承
- 当将一个类当做接口使用时, 那么实现这个接口的类,
必须实现
这个接口中所有方法
- 实现隐式接口使用
implements
关键字
main(List<String> args) {
SuperMan m = SuperMan();
m.flying();
}
/** 隐式接口
* Dart中没有哪一个关键字是来定义接口的
* 默认情况下所有的类都是隐式接口
* Dart只支持单继承
* 当将一个类当做接口使用时, 那么实现这个接口的类, 【必须实现】这个接口中【所有方法】
* 实现隐式接口使用【implements】关键字
*/
class Runner {
void running() {}
}
class Flyer {
void flying() {}
}
abstract class Animal {
void eating() {
print("动物吃东西");
}
void running();
}
// 单继承
class SuperMan extends Animal implements Runner, Flyer {
@override
void running() {
print("超人会奔跑");
}
@override
void flying() {
print("超人不仅能跑,还能飞");
}
}
Mixin混入
- 在通过
implements
实现某个类时,类中所有的方法
都必须被重新实现
(无论这个类原来是否已经实现过该方法)
- 这个在现实开发中不太现实,那么怎么解决这个问题呢?就是使用
Mixin混入
技术来实现
- 除了可以通过class定义类之外,也可以通过
mixin
关键字来定义一个类
- 只是通过mixin定义的类用于被其他类混入使用,通过
with
关键字来进行混入
main(List<String> args) {
SuperMan m = SuperMan();
m.running();
m.flying();
}
/** 隐式接口
* Dart中没有哪一个关键字是来定义接口的
* 默认情况下所有的类都是隐式接口
* Dart只支持单继承
* 当将一个类当做接口使用时, 那么实现这个接口的类, 【必须实现】这个接口中【所有方法】
* 实现隐式接口使用【implements】关键字
*/
mixin Runner {
void running() {
print("奔跑中...");
}
}
mixin Flyer {
void flying() {
print("飞翔中...");
}
}
abstract class Animal {
void eating() {
print("动物吃东西");
}
void running();
}
// 单继承,多混入
class SuperMan extends Animal with Runner, Flyer {
}
网友评论