七、对象
7.1. 对象创建
7.1.1. 属性
class Person{
String name = '张三'; // 最新版本的dart中需要初始化不可为null的实例字段
late int age; // 不初始化的话需要在属性前面加上late
/*省略部分代码*/
}
7.1.2. 默认构造函数
- 默认构造函数只能有一个
class Person{
/*省略部分代码*/
// Person(){print('构造函数');}
// Person():name='李四',age=24{print('构造函数');}
// Person(String name,int age){this.name=name;this.age=age;}
// Person(this.name,this.age);
Person(this.name,this.age){print('构造函数');}
}
7.1.3. 命名构造函数
- 命名构造函数可以有多个
class Person{
/*省略部分代码*/
Person.now() {print('我是命名构造函数');}
Person.now2() {print('我是命名构造函数');}
// Person.xxx(this.name, this.age);
}
7.1.4. getter和setter修饰符
class Rect{
late num height;
late num width;
Rect(this.height,this.width);
get area{return this.height*this.width;}
set areaHeight(value){this.height=value;}
}
void main(){
Rect r=new Rect(10,4);
// print("面积:${r.area()}");
r.areaHeight=6;
print(r.area);
}
7.1.5. 私有方法、私有属性
class Animal{
late String _name; //私有属性
late int age;
/*省略部分代码*/
String getName(){return this._name;}
void _run(){print('这是一个私有方法');}
execRun(){this._run(); //类里面方法的相互调用}
}
7.1.6. 静态成员、静态方法
class Person{
/*
1、使用static 关键字来实现类级别的变量和函数
2、静态方法不能访问非静态成员,非静态方法可以访问静态成员
*/
static String name = '张三';
int age=20;
static void show() {
print(name);
}
void printInfo(){ /*非静态方法可以访问静态成员以及非静态成员*/
// print(name); //访问静态属性
// print(this.age); //访问非静态属性
show(); //调用静态方法
}
static void printUserInfo(){//静态方法
print(name); //静态属性
show(); //静态方法
//print(this.age); //静态方法没法访问非静态的属性
// this.printInfo(); //静态方法没法访问非静态的方法
// printInfo();
}
/*省略部分代码*/
}
7.1.7. 实例化
import 'lib/Person.dart';
void main(){
var p1 = new Person('张三', 23);
print(p1.age);
p1.setAge(24);
p1.printInfo();
var d = new DateTime.now();
print(d);
var p2 = new Person.now();
print(p2.ageGet);
p2.ageSet = 25;
print(p2.age);
}
7.1.8. 总代码
// Person.dart
class Person{
String name = '张三';
int age=30;
Person(this.name,this.age){print('构造函数');}
Person.now(){print('命名构造函数');}
void printInfo(){
print("${this.name}---${this.age}");
}
void setAge(int age){
this.age = age;
}
get ageGet{
return this.age;
}
set ageSet(int age){
this.age = age;
}
work(){
print("${this.name}在工作...");
}
}
7.2. 对象操作符
- ? 条件运算符
- as 类型转换
- is 类型判断
- … 级联操作
Person p = new Person('张三', 20);
p?.printInfo(); // 如果p不为空,则执行printInfo()方法
if(p is Person){
p.name = '李四';
}
p.printInfo();
print(p is Object);
p..name = '王五'
..age = 23
..printInfo();
7.3. 封装、继承、多态
- 面向对象编程(OOP)的三个基本特征是:封装、继承、多态
-
封装:封装是对象和类概念的主要特性。封装,把客观事物封装成抽象的类,并且把自己的部分属性和方法提供给其他对象调用, 而一部分属性和方法则隐藏。
-
继承:面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
-
多态:允许将子类类型的指针赋值给父类类型的指针, 同一个函数调用会有不同的执行效果 。
/*
Dart中的类的继承:
1、子类使用extends关键词来继承父类
2、子类会继承父类里面可见的属性和方法 但是不会继承构造函数
3、子类能复写父类的方法 getter和setter
*/
class Web extends Person{
String sex='女';
Web(String name, int age, String sex) : super(name, age){
this.sex = sex;
}
Web.now(String sex) : super.now(){
this.sex = sex;
}
// 覆写父类的方法
void printInfo(){
print("${this.name} --- ${this.age} --- ${this.sex}");
}
run(){
print('run');
super.work(); //子类调用父类的方法
}
}
main(){
Web w = new Web('张三', 23, '男');
print(w.name);
w.printInfo();
}
7.4. 抽象、多态、接口
abstract class Animal{
eat(); // 抽象方法
run(); // 抽象方法
printInfo(){ // 普通方法
print('我是一个抽象类里面的普通方法');
}
}
class Dog extends Animal{
eat(){
print('小狗在吃骨头');
}
run(){
print('小狗在跑');
}
}
class Cat extends Animal{
eat(){
print('小猫在吃鱼');
}
run(){
print('小猫在跑');
}
}
7.4.1. 抽象
-
Dart中抽象类: Dart抽象类主要用于定义标准,子类可以继承抽象类,也可以实现抽象类接口。
- 抽象类通过abstract 关键字来定义
- Dart中的抽象方法不能用abstract声明,Dart中没有方法体的方法我们称为抽象方法。
- 如果子类继承抽象类必须得实现里面的抽象方法
- 如果把抽象类当做接口实现的话必须得实现抽象类里面定义的所有属性和方法。
- 抽象类不能被实例化,只有继承它的子类可以
-
extends抽象类 和 implements的区别:
- 如果要复用抽象类里面的方法,并且要用抽象方法约束自类的话我们就用extends继承抽象类
- 如果只是把抽象类当做标准的话我们就用implements实现抽象类
- 案例:定义一个Animal 类要求它的子类必须包含eat方法
Dog d1 = new Dog();
d1.eat();
d1.printInfo();
Cat c1 = new Cat();
c1.eat();
c1.printInfo();
7.4.2. 多态
-
允许将子类类型的指针赋值给父类类型的指针, 同一个函数调用会有不同的执行效果 。
-
子类的实例赋值给父类的引用。
-
多态就是父类定义一个方法不去实现,让继承他的子类去实现,每个子类有不同的表现。
Animal a1=new Dog();
a1.eat();
Animal a2=new Cat();
a2.eat();
7.4.3. 接口
7.4.3.1. 单个接口
- dart的接口没有interface关键字定义接口,而是普通类或抽象类都可以作为接口被实现,同样使用implements关键字进行实现。
- 如果实现的类是普通类,会将普通类和抽象中的属性的方法全部需要覆写一遍。
- 而因为抽象类可以定义抽象方法,普通类不可以,所以一般如果要实现像Java接口那样的方式,一般会使用抽象类。
// Db.dart
abstract class Db{
String url =""; // 数据库连接地址
add(data);
save();
delete();
}
// Mysql.dart
class Mysql implements Db{
String url;
Mysql(this.url);
add(data){print('mysql add'+data);}
save(){print('mysql save');}
delete(){print('mysql delete');}
}
Mysql mysql = new Mysql('xxxx');
mysql.add('123');
7.4.3.2. 多个接口
abstract class A{
late String name;
printA();
}
abstract class B{
printB();
}
class C implements A,B{
late String name;
printA() {print('printA');}
printB() {return null;}
}
void main(){
C c=new C();
c.printA();
}
7.4.3.3. mixins
-
mixins的中文意思是混入,就是在类中混入其他功能。在Dart中可以使用mixins实现类似多继承的功能
-
作为mixins的类只能继承自Object,不能继承其他类
-
作为mixins的类不能有构造函数
-
一个类可以mixins多个mixins类
-
mixins绝不是继承,也不是接口,而是一种全新的特性
-
class Person{
String name;
num age;
Person(this.name,this.age);
printInfo(){
print('${this.name}----${this.age}');
}
void run(){
print("Person Run");
}
}
mixin A {
String info="this is A";
void printA(){print("A");}
}
mixin B {
void printB(){print("B");}
}
class C extends Person with B,A{
C(String name, num age) : super(name, age);
}
void main(){
var c=new C();
c.printInfo();
c.printA();
c.printB();
print(c.info);
c.run();
print(c is C); //true
print(c is A); //true
print(c is B); //true
}
八、泛型
- 泛型:解决 类 接口 方法的复用性、以及对不特定数据类型的支持(类型校验)
8.1. 泛型方法
// 1. 不指定类型放弃了类型检查
getData(value){
return value;
}
// 2. 传入什么 返回什么。比如:传入number 类型必须返回number类型
T getData<T>(T value){return value;}
// getData<T>(T value){return value;}
void main(){
// print(getData(21));
// print(getData('xxx'));
// getData<String>('你好');
print(getData<int>(12));
}
8.2. 泛型类
class MyList<T> {
List list = <T>[];
void add(T value) {this.list.add(value);}
List getList() {return list;}
}
main() {
MyList l1=new MyList();
l1.add("张三");
l1.add(12);
l1.add(true);
print(l1.getList()); // [张三, 12, true]
}
8.3. 泛型接口
abstract class Cache<T> {
getByKey(String key);
void setByKey(String key, T value);
}
class FileCache<T> implements Cache<T> {
getByKey(String key) {return null;}
void setByKey(String key, T value)
{print("我是文件缓存 把key=${key} value=${value}的数据写入到了文件中");}
}
class MemoryCache<T> implements Cache<T> {
getByKey(String key) {return null;}
void setByKey(String key, T value)
{print("我是内存缓存 把key=${key} value=${value} -写入到了内存中");}
}
void main() {
// MemoryCache m=new MemoryCache<String>();
// m.setByKey('index', '首页数据');
MemoryCache m = new MemoryCache<Map>();
m.setByKey('index', {"name": "张三", "age": 20});
}
九、库
9.1. 导入库
- 实际开发需要模块化。
- 库的使用时通过import关键字引入的。
- library指令可以创建一个库。
- 每个Dart文件都是一个库,即使没有使用library指令来指定。
Dart中的库主要有三种:
1、我们自定义的库:import ‘lib/xxx.dart’;
2、系统内置库
- import ‘dart:math’;
- import ‘dart:io’;
- import ‘dart:convert’;
3、Pub包管理系统中的库
- https://pub.dev/packages
- https://pub.flutter-io.cn/packages
- https://pub.dartlang.org/flutter/
- 需要在自己想项目根目录新建一个pubspec.yaml
- 在pubspec.yaml文件 然后配置名称 、描述、依赖等信息
- 然后运行
flutter pub get
获取包下载到本地- 项目中引入库 import ‘package:http/http.dart’ as http; 看文档使用
// pubspec.yaml
name: xxx
description: A new flutter module project.
dependencies:
http: ^1.2.0
date_format: ^2.0.7
environment:
sdk: '3.2.6'
9.2. 库的使用(请求数据httpClient)
9.2.1. 使用本地库
import 'dart:io';
import 'dart:convert';
void main() async{
var result = await getDataFromZhihuAPI();
print(result);
}
//api接口: http://news-at.zhihu.com/api/3/stories/latest
getDataFromZhihuAPI() async{
//1、创建HttpClient对象
var httpClient = new HttpClient();
//2、创建Uri对象
var uri = new Uri.http('news-at.zhihu.com','/api/3/stories/latest');
//3、发起请求,等待请求
var request = await httpClient.getUrl(uri);
//4、关闭请求,等待响应
var response = await request.close();
//5、解码响应的内容
return await response.transform(utf8.decoder).join();
}
9.2.2. 使用Pub包
import 'dart:convert' as convert;
import 'package:http/http.dart' as http;
import 'package:date_format/date_format.dart';
main() async {
String url = "http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20&page=1";
Uri uri = Uri.parse(url);
// Await the http get response, then decode the json-formatted responce.
var response = await http.get(uri);
if (response.statusCode == 200) {
var jsonResponse = convert.jsonDecode(response.body);
print(jsonResponse);
} else {
print("Request failed with status: ${response.statusCode}.");
}
}
9.2.3. 使用两个同名包
import 'lib/Person1.dart';
import 'lib/Person2.dart' as lib;
main(List<String> args) {
Person p1=new Person('张三', 20);
p1.printInfo();
lib.Person p2=new lib.Person('李四', 20);
p2.printInfo();
}
9.2.4. 部分导入
- show:只导入需要的部分。
- hide:隐藏不需要的部分。
// import 'lib/myMath.dart' show getAge;
import 'lib/myMath.dart' hide getName;
void main(){
// getName();
getAge();
}
9.2.5. 延迟加载
- 意义:需要的时候再进行加载。
- 优点:可以减少APP的启动时间。
- deferred as:使用关键字来指定懒加载。
- loadLibrary():当需要使用的时候,需要使用方法来加载。
import 'package:deferred/hello.dart' deferred as hello;
greet() async {
await hello.loadLibrary();
hello.printGreeting();
}
9.3. 异步
- async:让方法变成异步。
- await:等待异步方法执行完成。(只有async方法才能使用await关键字调用方法)
void main() async{
var result = await testAsync();
print(result);
}
//异步方法
testAsync() async{
return 'Hello async';
}
十、关键字
10.1 可空类型
- ? 可空类型
String? getData(apiUrl){
if(apiUrl!=null){
return "this is server data";
}
return null;
}
void printLength(String? str){
try {
print(str!.length);
} catch (e) {
print("str is null");
}
}
void main(args) {
print(getData("http://www.itying.com")); // this is server data
rint(getData(null)); // null
printLength("str"); // 3
printLength(null); // str is null
}
10.2. 非空断言
- ! 类型断言:如果str不等于null 会打印str的长度,如果等于null会抛出异常。
// ! 类型断言
String? str="this is str";
str=null;
print(str!.length);
10.3. required
- 主要用于允许根据需要标记任何命名参数(函数或类),使得它们不为空。因为可选参数中必须有个 required 参数或者该参数有个默认值。
class Person {
String name;
int age;
Person({required this.name,required this.age}); //表示 name 和age 必须传入
String getName() {return "${this.name}---${this.age}";}
}
String printInfo(String username, {required int age, required String sex}) {//行参
return "姓名:$username---性别:$sex--年龄:$age";
}
void main(args) {
print(printUserInfo('张三',age: 20,sex: "女"));
Person p=new Person(
name: "张三",
age: 20
);
print(p.getName());
}