目录
- 能够定义并使用Dart的类
- 类的定义
- 构造函数
- 私有属性和方法
- 继承
- mixin
- 异步编程
- Future
- Future链式调用
- async - await
- dynamic类型
- 泛型
- 异常
能够定义并使用Dart的类
Dart是一门面向对象的编程语言,所有的对象都是类的实例 通过类我们可以对数据和方法进行封装复用
学习内容:
- 类的定义
- 构造函数
- 私有属性和方法
- 继承
- mixin
类的定义
使用 class 关键字声明一个类,所有的类都是继承自 Object 类
类的组成:属性 和 方法
属性和方法都是通过 . 访问的
例子:定义一个Person类,属性是名字和年龄,方法是吃饭
整体代码
void main() {
// 创建Person对象
// Person person = Person();
// // 给属性赋值
// person.name = '张三';
// person.age = 18;
// 使用自定义类名构造函数创建对象
// Person person = Person('李四', 19);
// 使用命名构造函数创建对象
// Person person = Person.withName('王五');
// 使用工厂构造函数创建对象
// Person person = Person.withInfo('赵六', 21);
Person person = Person.withInfo('赵六', -21);
print('我叫 ${person.name} 今年 ${person.age}');
Person person1 = Person.withAge(20);
print(person1.age);
// 调用方法
person.eat();
}
// 例子:定义Person类,属性:名字和年龄,方法:吃饭
class Person {
// 默认的构造函数(无参数,默认隐藏)
// Person() {
// print('我是默认的构造函数');
// }
// 自定义类名构造函数:可以有参数
// 注意点:与类同名的构造函数只能有一个,如果自定义了类名构造函数,那么默认的构造函数就失效
// Person(String name, int age) {
// this.name = name;
// this.age = age;
// }
// 简写:自定义类名构造函数时,如果函数的参数和类的属性同名
Person(this.name, this.age);
// 定义命名构造函数
// Person.withName(String name) {
// this.name = name;
// }
// 简写
Person.withName(this.name);
Person.withAge(this.age);
// 定义工厂构造函数
// factory Person.withInfo(String name, int age) {
// // 需要手动的创建对象并返回
// return Person(name, age);
// }
// 例子:如果age < 0,那么person对象的年龄默认设置为0
factory Person.withInfo(String name, int age) {
// 需要手动的创建对象并返回
return age < 0 ? Person(name, 0) : Person(name, age);
}
// 属性
String? name;
int? age;
// 方法
void eat() {
print('我是干饭人');
}
}
构造函数
创建对象时调用的函数,常用的构造函数有:
- 类名构造函数
- 命名构造函数
- 工厂构造函数
类名构造函数,
与类同名的构造函数
- 默认构造函数(无参数,默认隐藏)
- 自定义类名构造函数(可以有参数)
注意点:类名构造函数,只能有一个
,如果自定义了类名构造函数,那么默认的类名构造函数就无效了
命名构造函数
,可以为类提供多个不同的构造函数
定义方式:类名.函数名() {}
// 简写:自定义类名构造函数时,如果函数的参数和类的属性同名
Person(this.name, this.age);
// 定义命名构造函数
// Person.withName(String name) {
// this.name = name;
// }
// 简写
Person.withName(this.name);
Person.withAge(this.age);
工厂构造函数
,不会直接创建对象,而是在构造函数内部通过代码来决定要创建的对象
定义方式: 使用 factory 关键字声明工厂构造函数
// 定义工厂构造函数
// factory Person.withInfo(String name, int age) {
// // 需要手动的创建对象并返回
// return Person(name, age);
// }
例子:如果创建Person对象时,age < 0,则该Person对象的年龄默认设置为0
// 例子:如果age < 0,那么person对象的年龄默认设置为0
factory Person.withInfo(String name, int age) {
// 需要手动的创建对象并返回
return age < 0 ? Person(name, 0) : Person(name, age);
}
使用场景:当需要根据条件来决定要返回的对象时,比如:单例
私有属性和方法
- 私有属性和方法:
在类中定义,不对外暴露,不能被其他Dart文件访问的属性和方法 - 如何定义私有属性和方法:
使用 _ 定义属性和方法
// 导入Dart文件、库
import '28_类_私有属性和方法.dart';
void main() {
// 创建Dog对象
Dog dog = Dog();
dog.name = '旺财';
print(dog.name);
// 私有属性调用失败
// dog._age;
dog.eat();
// 私有方法调用失败
// dog._run();
}
继承
通过继承可以让子类拥有父类的一些属性和方法。如何实现继承:
- 如何实现继承:
- 子类使用
extends
关键字继承父类
- 子类使用
- 继承的特点:
- Dart的继承是单继承,一个子类只能有一个父类
- 子类只会继承父类里面可见的属性和方法,不会继承私有属性和方法
- 子类只会继承父类默认的构造函数,不会继承其他构造函数
- 子类可以重写父类的方法,也可以使用
super
调用父类方法
void main() {
// 创建猫
// Cat cat = Cat();
// cat.name = 'Tom';
Cat cat = Cat('Tom');
print(cat.name);
cat.eat();
cat.walk();
// 创建鱼
// Fish fish = Fish();
// fish.name = '鲨鱼';
Fish fish = Fish('鲨鱼');
print(fish.name);
fish.eat();
fish.swim();
}
// 猫,吃饭和走路
class Cat extends Animal {
Cat(String name) : super(name);
// String? name;
// void eat() {
// print('eat');
// }
// 重写父类的方法
void eat() {
// 执行子类自己的逻辑
print('执行子类自己的逻辑');
// 使用super去调用父类的方法
// super.eat();
}
void walk() {
print('walk');
}
}
// 鱼,吃饭和游泳
class Fish extends Animal {
// 定义子类自己的构造函数,并且使用super调用父类的构造函数传递数据
Fish(String name) : super(name);
// String? name;
// void eat() {
// print('eat');
// }
void swim() {
print('swim');
}
}
// 定义一个父类,父类里面有其他类都有的属性和方法
// 使用继承,让子类继承父类,从而子类就自动拥有了父类的属性和方法
class Animal {
// 自定义类名构造函数
// 如果父类自定义构造函数,那么子类继承不到,所以子类需要自己定义构造函数
Animal(this.name);
String? name;
void eat() {
print('eat');
}
}
// class Animal1 {
// String? age;
// void sleep() {
// print('eat');
// }
// }
mixin
mixin
可以理解为扩展类,可以为类扩展功能,而不需要使用继承,类似Vue里面的混入。
如何定义并使用 mixin
:
- 定义:
mixin
关键字 - 使用:
with
关键字
mixin
的特点:
- 可以扩展属性和方法
- 不能被实例化,不能被继承
void main() {
Person person = Person();
// name是继承的
person.name = '张三';
print(person.name);
// height是通过mixin扩展的
person.height = 180.0;
print(person.height);
// eat()是继承的
person.eat();
// walk()是通过mixin扩展的
person.walk();
person.study();
// mixin不能被实例化,不能被继承
// WalkMixin();
}
// mixin可以使用多个
mixin StudyMixin {
void study() {
print('study');
}
}
// 定义mixin
mixin WalkMixin {
double? height;
void walk() {
print('walk');
}
}
// 人,吃饭和走路
class Person extends Animal with WalkMixin, StudyMixin {
// String? name;
// void eat() {
// print('eat');
// }
// void walk() {
// print('walk');
// }
}
// 猫,吃饭和走路
class Cat extends Animal with WalkMixin {
// void walk() {
// print('walk');
// }
}
// 鱼,吃饭和游泳
class Fish extends Animal {
void swim() {
print('swim');
}
}
// 定义基类:动物
class Animal {
String? name;
void eat() {
print('eat');
}
// void walk() {
// print('walk');
// }
}
异步编程
能够使用Dart异步编程解决耗时操作阻塞程序的问题
在Web端和APP中,有很多耗时操作都需要 异步执行
Web端的异步解决方案是 Promise,再配合 async – await 更能以同步的方式编写异步代码
Dart也同样提供了异步解决方案 Future ,也可以配合 async – await 使用
学习内容:
1.Future
2.async - await
Future
- Future是一个表示延迟计算的对象。代表一些计算将异步进行
- Future会在耗时操作执行完毕前直接返回,而不会等待耗时操作执行结束
- 例子:模拟耗时操作阻塞程序,并使用Future解决程序阻塞问题
// 模拟耗时操作阻塞程序的问题,并使用Future解决阻塞问题
print('开始喽');
Future(() {
// 耗时任务执行的地方
sleep(Duration(seconds: 5));
// 故意编写的异常代码(测试)
// dynamic str = 'hehe';
// str.haha();
// 返回异步任务执行的结果
return '假装这是异步任务执行的结果';
}).then((value) {
// 监听异步任务执行结束
print(value);
}).catchError((e) {
// 捕获异常信息
print(e);
});
Future链式调用
例子:用户先登录并获取用户信息,再保存用户信息
// Future链式调用
// 用户先登录拿到用户信息,然后再保存用户信息
Future login(String name, String password) {
return Future(() {
sleep(Duration(seconds: 2));
print('登录操作');
return 'userInfo';
});
}
Future saveUserInfo(String userInfo) {
return Future(() {
sleep(Duration(seconds: 2));
print('保存用户信息');
return 'OK';
});
}
// Future链式调用
login('张三', '123456').then((value) {
saveUserInfo(value);
});
print('假装这是个不能被阻塞的代码');
async - await
- Future 配合 async – await 以同步的方式编写异步代码
- 例子:用户先登录并获取用户信息,再保存用户信息
// Future链式调用
// 用户先登录拿到用户信息,然后再保存用户信息
Future login(String name, String password) {
return Future(() {
sleep(Duration(seconds: 2));
print('登录操作');
return 'userInfo';
});
}
Future saveUserInfo(String userInfo) {
return Future(() {
sleep(Duration(seconds: 2));
print('保存用户信息');
return 'OK';
});
}
// Future链式调用
// login('张三', '123456').then((value) {
// saveUserInfo(value);
// });
// async await
void doLogin() async {
String userInfo = await login('李四', '123456');
await saveUserInfo(userInfo);
}
doLogin();
print('假装这是个不能被阻塞的代码');
dynamic类型
能够知道dynamic类型的特点
在Dart中,虽然有类型推断和类型检查
但是,还可以使用 dynamic 关键字关闭变量的类型检查
特点:
编码灵活,可以保存任意类型的数据
容易产生 NoSuchMethodError 的异常
void main() {
int a = 15;
// a = 'itcast';
a = 20;
// dynamic会关闭编译器的类型检查
dynamic b = 100;
b = 'itheima';
print(b);
// b.haha();
// b.hehe;
}
泛型
能够知道泛型的作用
泛型是指类型的不确定性,数据具体的类型可以在使用时确定
- 使用泛型可以限定类型
// 泛型限定数据的类型:List Map
// 保存视频分类名称时,不应该出现100 true这样类型的数据
// List categories = ['居家', '美食', 100, true];
List<String> categories = ['居家', '美食'];
使用泛型可以明确约束列表元素的类型
使用泛型可以明确约束字典的key和value的类型
Map<String, String> category = {
'id': '1',
'name': '居家',
};
- 使用泛型可以减少重复代码
// 封装方法:接收什么类型的数据,就返回什么类型
T demo<T>(T parm) {
return parm;
}
异常
能够知道如何捕获并处理异常
- 如何捕获异常:
使用关键字 try catch 捕获并处理异常
finally:无论是否有异常都会执行到的语句块
// 捕获异常:try catch
// try {
// dynamic name = 'zzm';
// name.haha();
// } catch (e) {
// print(e);
// } finally {
// // 无论是否有异常都会执行这个代码块
// print('finally');
// }
- 如何手动抛出异常:使用关键字 throw 手动抛出异常
// 手动抛出异常:判断字符串是否相等,如果不相等手动抛出异常
try {
String str = 'zzm';
if (str == 'zxc') {
print('ok');
} else {
// 手动抛出异常
throw '字符串不相等';
}
} catch (e) {
print(e);
}