这个转自我自己的有道云 想看图片去那里
文档:Day2_26 Dart 面向对象 异步语法.md
链接:http://note.youdao.com/noteshare?id=6bfd9ee6019989e583ecbb5009342f84&sub=C287257DA6244F2F9366855BE54A320B
Dart语言很重要的一个特质就是, 它是一个面向对象的语言
所以我们必须将它的一些语法搞清楚
这个语言非常的新, 所以它的一些技术就是为了解决之前的语言没有办法解决的痛点
class 类名 {
修饰词(final/var/const) 变量类型(String/int/double...) 属性名
返回值 方法名(参数列表) ...
}
main(List args) {
print(new Person("test", 12));
print(Person1("test", 13));
}
class Person {
String name;
int age;
Person(String name, int age ) {
this.name = name;
this.age = age;
}
@override
String toString() {
// TODO: implement toString
return "name = $name, age = $age";
}
}
class Person1 {
String name;
int age;
Person1(this.name, this.age);
@override
String toString() {
// TODO: implement toString
return "name = $name, age = $age";
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-06G5zPzH-1582795200894)(FAF91B9E80D74B7F97ADE2882C39BF4E)]
为什么要用这个玩意
因为我们的Dart没有函数重载, 所以如果想要重载函数我们就需要命名构造函数
main(List args) {
print(new Person());
print(new Person.withArgments("test", 12));
print(new Person.withMapArgments({"name": "test2", "age": 123}));
}
class Person{
String name;
int age;
Person() {
name = "";
age = 0;
}
Person.withArgments(String name, int age) {
this.name = name;
this.age = age;
}
Person.withMapArgments(Map map) {
name = map["name"];
age =map["age"];
}
@override
String toString() {
// TODO: implement toString
return "name = $name, age = $age";
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f0egh9FJ-1582795200897)(9B8D5B05519742DBA3DF94A52E3323F7)]
构造函数的简化写法就是 Person(this.name) 其实也就是简化的初始化列表的写法
我们可以在初始化列表中初始化 final定义的变量
import 'dart:math';
main(List args) {
var p1 = Point(2.0, 3.0);
print(p1);
var p = Person2("why");
print(p.name);
print(p.age);
var p2 = Person2("why", age: 30);
print(p2.name);
print(p2.age);
}
class Point {
final num x;
final num y;
final num distance;
// 错误的写法
// 因为在执行下面的代码的时候对象的初始化已经完成了, 所以不能对它再进行赋值
// Point(this.x, this.y) {
// distance = sqrt( x * x + y * y);
// }
// 正确的写法
Point(this.x, this.y) : distance = sqrt(x * x + y * y);
@override
String toString() {
// TODO: implement toString
return "x = $x, y = $y, distance = $distance";
}
}
class Person2 {
final String name;
final int age;
Person2(this.name, {this.age = 10});
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mrgegsBL-1582795200897)(0F095807073E462A8EE8ECBE5A609138)]
直接的区别就是, 初始化列表里面是可以写一些语句的
但是可选参数的默认值是不行的
main(List args) {
print( Person("why").age);
// 可见这种写法没有问题 Person(String name, {this.age = 10})
print(Person("why", age: 20).age);
}
const temp = 20;
class Person {
final String name;
// final 意味着这个age只能赋值一次
final int age;
// 初始化列表这里是可以写一些语句的
// 以下的这个初始化列表里的语句含义和{int age = 10} 是一样的
// 如果我们创建对象的时候, 我们就使用传入的age, 如果没有就使用默认值
// 那我们能不能这样做呢
// Person(this.name, {int age}) : this.age = age ?? 10 {
// // this.age = 10; 不能在里面进行初始化
// }
// 可见这种写法没有问题
// 而且在上面的这种需求之下这种做法是最好的
// 但是我们下面的这种写法它有一个局限性
// flutter 经常用初始化列表的方式 初始化变量的方式
// 因为初始化列表里面可以写语句所以在里面做一些初始化初始化变量的方式dart很喜欢这样做
// 但是为什么不直接在对应的位置给它默认值呢
// 在这个里面做初始化只能给它赋值一个确定的值
// 这个参数列表里面只能做赋值操作 或者是 虽然后面用了一些其它的, 但是整个的语句话还是一个赋值语句
// Person(this.name, {this.age = 10});
// Person(this.name, {this.age = temp ?? 30});
// 但是如果我们想要做一些三元运算符之类的操作 我们就在这个里面写就不行了
// 而且这样比较好看
// 就像下面这样如果想要做一个判断再赋值 还是初始化列表比较方便
Person(this.name, {int age}) : this.age = temp > 20 ? 30 : 50 {
}
// Person(this.name, {int age = 10}); 这样初始化只能初始化普通的非final类变量
// 保留
// Person(this.name, {this.age = 10});
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-COg8sQUy-1582795200898)(BEAD4574BF14497D89E2914CA6D729BC)]
同时我们也可以看到dart源码里面很多的初始化列表的使用方式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TnJ8JwzI-1582795200898)(FB3DE271DA144FFCBF8E7EDE09D02603)]
我们希望在构造函数中使用这个类的其他构造函数
我们就可以使用重定向构造函数
其实也是为了解决没有函数重载带来的问题
main(List args) {
print( Person.fromName("test") );
}
class Person {
String name;
int age;
Person(this.name, this.age);
Person.fromName(String name) : this(name, 0);
@override
String toString() {
// TODO: implement toString
return "name = $name, age = $age";
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BcL1KuY3-1582795200898)(F1995644040C4BF4907045B6DD3A1F1F)]
常量类的构造函数 可以做到如果传入同样的参数 就可以得到同样的对象
这样做可以节省内存, 避免一个对象多次创建
main(List args) {
var p1 = Person("same");
// 这个省略的是new
var p2 = new Person("same");
// identical(a, b) 这个函数可以判断
// a, b两个变量是否指向同一个对象
print(identical(p1, p2));
const p3 = Person2("same");
// 这个省略的是const
const p4 = const Person2("same");
print(identical(p3, p4));
}
class Person {
String name;
Person(name) {
this.name = name;
}
}
class Person2 {
final String name;
final int age;
// const Person2(this.name);
// 相当于 多个参数用逗号隔开
const Person2(name) : this.name = name, this.age = 10;
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kqWV7iPv-1582795200899)(DBF6F2434A0B42B3AF124F04FE7FD427)]
普通构造函数会默认返回创建的对象
工厂函数需要手动返回一个对象, 不管这个对象是自己创建的还是别的
main(List args) {
print(identical(Person("test"), Person("test")));
}
class Person {
String name;
static final Map _cache = {};
factory Person(String name) {
if( _cache.containsKey(name) ) {
return _cache[name];
} else {
final p = Person._internal(name);
_cache[name] = p;
return p;
}
}
Person._internal(this.name);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lj5n3ynd-1582795200899)(B58AE8E883624502A84ECAF3946EED73)]
工厂构造函数和常量构造函数有相似的作用 但是他们是不一样的
另外讲一个vscode的快捷键 alt + shift + 向下, 向下拷贝
main(List args) {
var p1 = Person("why", "22");
var p2 = Person("why", "22");
print("${identical(p1, p2)}"); // false
const p3 = Person2("why");
const p4 = Person2("why");
print(identical(p3, p4));
}
// 常量构造函数
// 需求:放入相同color的参数的时候就会返回相同的对象
// 放入相同name的时候也会产生相同的对象
// 常量构造函数一般一个函数只能有一个常量参数 如果有多个就没有原来的功能了
class Person {
final String name;
final String age;
const Person(this.name, this.age);
}
class Person2 {
final String name;
const Person2(name): this.name = name;
// const Person2(this.name);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m204Ujt8-1582795200899)(F8187E5F863C4FF99E990C24B9EF9E77)]
main(List args) {
var p5 = Person3.withName("why");
var p6 = Person3.withName("why");
print(identical(p5, p6));
}
class Person3 {
final String name;
final String color;
// _作用就像是private 只能在本模块(文件)中使用
// 这里存储的是Person对象的地址
static Map _nameMap = {};
static Map _colorMap = {};
// 工厂构造函数需要手动返回对象
factory Person3.withName(String name) {
if( _nameMap.containsKey(name) ) {
return _nameMap[name];
} else {
var p3 = Person3._internal(name, "default");
// 这里传递的是指针
_nameMap[name] = p3;
return p3;
}
}
factory Person3.withColor(String color) {
if(_colorMap.containsKey(color)) {
return _colorMap[color];
} else {
var p3 = Person3._internal("default", color);
_colorMap[color] = p3;
return p3;
}
}
Person3._internal(this.name, this.color);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p8uEYsrL-1582795200900)(5218F14ADA994D73BFC50FE8A19459E9)]
默认情况下, Dart中定义的属性是可以被外界直接访问的
但是如果我们希望监控这个类的属性被访问的过程, 这个时候我们就可以使用setter 和 getter了
main(List args) {
var p1 = Person("why");
p1.name = "test";
print(p1.name);
p1.setName = "name";
print(p1.getName);
}
class Person {
String name;
Person(this.name);
// 这个方法的名字虽然可以乱取, 但是还是建议就这样取
// setter
set setName(String name) => this.name = name;
// set setName(String name) {
// this.name = name;
// }
// getter
String get getName => name;
// 注意啊getter 不需要传参
// String get getName {
// return name;
// }
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d2p8ccaK-1582795200900)(EC3B81A08B604386B7300D66462BCB9E)]
面向对象的一大特性就是, 继承可以减少我们的代码量, 可以多态的使用前提
Dart 的继承使用extends关键字, 字类中使用super来访问父类
父类中的所有成员都会被继承, 但是构造方法除外 基本上和java没有区别
如果还有东西想要在初始化列表的地方初始化, 我们可以继续在super后面加,添加 : super(color), this.age = age;
main(List args) {
}
class Animal {
int age;
Animal(this.age);
}
class Person extends Animal {
String name;
Person(this.name, int age): super(age);
@override
String toString() {
// TODO: implement toString
return "name = $name, age = $age";
}
}
dart的抽象类和java还不太像, 但是大致一样
main(List args) {
}
abstract class Shape {
// 可以有方法的实现
int getArea();
String getInfo() {
return "形状";
}
}
main(List args) {
}
abstract class Shape {
// 可以有方法的实现
int getArea();
String getInfo() {
return "形状";
}
}
class Rectangle extends Shape {
@override
int getArea() {
// TODO: implement getArea
return null;
}
// 子类构造函数不能调用父类的工厂函数
}
但是我们可以通过工厂函数返回它的字类对象
所以dart的源码里面有些时候会看到直接用抽象类的构造函数返回抽象类的对象
main(List args) {
var s1 = Shape();
print(s1);
}
abstract class Shape {
// 可以有方法的实现
int getArea();
String getInfo() {
return "形状";
}
factory Shape() {
return null;
}
}
同时还有external 关键字
这个东西的作用是将方法的声明和实践分离 同时使用的还有@patch 和 @servlet一样是一个注释
有些时候你看到dart源码里面它没有实现其实是放到其他的地方去了
Dart 中没有一个关键字是用来定义接口的
没有诸如 interface/protocol 的关键字
默认情况下所有的类都是隐式接口
main(List args) {
var superM = SuperMan();
superM.flying();
superM.running();
}
class Runner {
void running() {
print("Runner running");
}
}
class Flyer {
void flying( ) {
print("Flyer flying");
}
}
class SuperMan implements Flyer, Runner {
@override
void flying() {
// TODO: implement flying
}
@override
void running() {
// TODO: implement running
}
}
执行的重写的代码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MM3mSmKF-1582795200901)(60B621AF74AE48D083A7A4DA45AD2BFD)]
接口主要是为了解决一个多继承的问题, 多继承使用起来问题太多, 接口就比较好
main(List args) {
var superM = SuperMan();
superM.flying();
superM.running();
}
class Runner {
void running() {
print("Runner running");
}
}
class Flyer {
void flying( ) {
print("Flyer flying");
}
}
class Animal {
void eating() {
print("eating Animal");
}
void running() {
print("running");
}
}
class SuperMan extends Animal implements Runner {
}
虽然继承 使用接口抽象类都很好 可以大幅度的减少代码的行数, 但是我们还是想要直接使用这些方法 我们使用接口就可以了
我们可以使用混入
main(List args) {
var s1 = SuperMan();
s1.running();
}
mixin Runner {
void running() {
print("running");
}
}
mixin Flyer {
void flying() {
}
}
class SuperMan with Runner, Flyer {
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3mp9Feuw-1582795200901)(9F7D25D11A274ADB961DAF618A95F2AE)]
main(List args) {
Person.count = 10;
print(Person.count);
Person.staticMethod();
}
class Person {
// 普通属性
String name;
// 类属性
static int count = 0;
// 类方法
static void staticMethod() {
print("method");
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JX5XHOb3-1582795200901)(B9ADBED303C44388881C51613BBD6E1E)]
枚举是用enum定义的
有些语言没有这个东西 比如js 没有枚举其实是它的缺陷, 所以ts对它做了扩充
main(List args) {
final color = Colors.red;
switch (color) {
case Colors.red:
print("这个是红色");
break;
case Colors.blue:
print("这个是蓝色");
break;
default:
}
print(Colors.values);
print(Colors.red.index);
print(Colors.red.toString());
}
// 枚举它有固定的值
// 使用它最大的好处就是因为它类型安全
// 它能有的值就这些 所以它安全
enum Colors {
red,
blue
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PXvBo0YV-1582795200902)(E7C4A90573DE4606BFAE0D5044C62BA2)]
一般来说一个dart文件就是一个库
// import "dart:io";
// import "dart:isolate";
// import "dart:async";
// import "dart:math";
// 系统的库: import "dart:库的名字"
// 不是主要的库 就需要引入
import 'dart:math';
main(List args) {
// 系统库是不需要导入的 dart:core 是核心库是默认会导入的
final num1 = 20;
final num2 = 30;
print(min(num1, num2));
}
我们建立这样一个目录
+ 库的使用
+ utils
math_utils.dart
使用自定自定义的库.dart
math_utils.dart
int sum(int num1, int num2) {
return num1 + num2;
}
double mul(double num1, double num2) {
return num1 * num2;
}
然后我们就想要在自建的库里面使用这几个东西
使用自定义的库.dart
import 'utils/math_utils.dart';
main(List args) {
print(sum(10, 20));
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AFePxziL-1582795200902)(F283490FDA954C93969AD4CCFB9562E9)]
/**
* 1. 补充一:如果命名冲突 我们可以通过 as 关键字给库起别名
*/
import 'utils/math_utils.dart' as mUtils;
main(List args) {
print(mUtils.sum(10, 20));
}
void sum(num1 , num2 ) {
print(num1 + num2);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OXj6vCdS-1582795200902)(1B97133EDEFA481482821A5D818CA6EA)]
/**
* 1. 补充一:如果命名冲突 我们可以通过 as 关键字给库起别名
* 2. 补充二: 默认情况下是导入库中的所有的内容
*/
// import 'utils/math_utils.dart' as mUtils;
import "utils/math_utils.dart";
main(List args) {
// print(mUtils.sum(10, 20));
print(sum(10, 20));
print(mul(10, 20));
}
// void sum(num1 , num2 ) {
// print(num1 + num2);
// }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xzzMakQ2-1582795200902)(0B3D812D0B4D4C35B45551A267DE0D23)]
但是如果你只想导入某些东西, 或者某个东西呢
我们可以使用show, hide关键字
/**
* 1. 补充一:如果命名冲突 我们可以通过 as 关键字给库起别名
* 2. 补充二: 默认情况下是导入库中的所有的内容
* 但是如果不想都导入的话
* * show: 指定要导入库
* * hide: 隐藏某个要导入的内容, 导入其他内容
*/
// import 'utils/math_utils.dart' as mUtils;
// import "utils/math_utils.dart";
import "utils/math_utils.dart" show sum, mul;
import "utils/math_utils.dart" hide sum, mul;
main(List args) {
// print(mUtils.sum(10, 20));
print(sum(10, 20));
print(mul(10, 20));
}
// void sum(num1 , num2 ) {
// print(num1 + num2);
// }
一般情况我们是一个一个导入
/**
* 1. 补充一:如果命名冲突 我们可以通过 as 关键字给库起别名
* 2. 补充二: 默认情况下是导入库中的所有的内容
* 但是如果不想都导入的话
* * show: 指定要导入库
* * hide: 隐藏某个要导入的内容, 导入其他内容
*/
// import 'utils/math_utils.dart' as mUtils;
// import "utils/math_utils.dart";
import "utils/math_utils.dart" show sum, mul;
import "utils/math_utils.dart" hide sum, mul;
import 'utils/data_utils.dart';
main(List args) {
// print(mUtils.sum(10, 20));
print(sum(10, 20));
print(mul(10, 20));
print(dataFormat());
}
但是如果文件多了怎么办呢
那难道我们一个一个的导入吗
我们可以用part关键字拆分(但是这个官方已经不建议再用了) 然后一次拆分
这个东西用起来非常麻烦, dart也发现这个东西不好用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ouzl7Mtm-1582795200903)(6985997B015244DD92F176D1EEE3F364)]
他们搞了一个东西让很多文件可以通过一个文件一次性引入
这样我们用的时候就可以一次性引入
文件结构
+ 库的使用
+ utils
math_utils.dart
data_utils.dart
utils.dart
使用自定自定义的库.dart
utils.dart
export "./data_utils.dart";
export "./math_utils.dart";
这样我们只需要引入一次就把两个文件都引入了
相当于给它抽取除一个公共的头文件
使用自定自定义的库.dart
import "utils/utils.dart";
main(List args) {
// print(mUtils.sum(10, 20));
print(sum(10, 20));
print(mul(10, 20));
print(dataFormat());
}
math_utils.dart
int sum(int num1, int num2) {
return num1 + num2;
}
double mul(double num1, double num2) {
return num1 * num2;
}
// 下划线是区分私有和公共的一种方式
int _min(int num1 , int num2) {
return num1 > num2 ? num2 : num1;
}
使用自定自定义的库.dart
import "utils/utils.dart";
main(List args) {
// print(mUtils.sum(10, 20));
print(sum(10, 20));
print(mul(10, 20));
print(dataFormat());
// _min(10,20); 在外面访问就会博爱错
}
如果外面访问就会直接报错
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QONnptsK-1582795200903)(FB54D611E1CF4316A4597EF2044B760C)]
这个使用第三方库和node很想
node管理第三方的库是用了一个package.json来管理
叫做
pubspec.yaml 就是通过这个东西来管理的
它有几个属性 嘛差不多就是名字的意思
我们要使用第三方的库 我们就可以到这个 pub.dev 去
这个网站是必须记住的
name: codewhy
description: a dart library
dependences:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sNeYFQZk-1582795200903)(1B188382D7E04D98A8F0E875B94207E7)]
我们就安装一个 http
找到以后我们点击 installing
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PTjCDsiz-1582795200904)(5BE1DFB7247D4DF8A41899B47BBBA7F2)]
就发现有个dependencies
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4elLR6ri-1582795200904)(D715958010AA48C09E178898E3BE9817)]
我们就可以来到对应的位置
name: codewhy
description: a dart library
dependencies:
http: ^0.12.0+4
然后进入对应的文件夹 pub get 就可以了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6j48Us1O-1582795200905)(FC5903FE618E4D9589C51328F556B46D)]
一旦完成, 你就会发现多了几个文件 都是一些日志信息
下面我们用他的代码来试一试吧
import 'package:http/http.dart' as http;
main(List args) async {
var url = 'http://49.234.222.253:8080/sDemo/register/checkCompanyRigster.do';
var response = await http.post(url, body: {"uid" : "1"});
print('Response status: ${response.statusCode}');
print('Response body: ${response.body}');
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dn2cOWag-1582795200905)(F9C43B9C1FFE4078A5255AB97276ADB9)]