关于flutter:Dart基础知识汇总

4次阅读

共计 24278 个字符,预计需要花费 61 分钟才能阅读完成。

1 介绍

Dart 是由谷歌开发的计算机编程语言, 它能够被用于 web、服务器、挪动利用 和物联网等畛域的开发。

Dart 诞生于 2011 年,号称要取代 JavaScript。然而过来的几年中始终不温不火。直到 Flutter 的呈现当初被人们从新器重。

要学 Flutter 的话咱们必须首先得会 Dart。

官网:https://dart.dev/

2 环境搭建

要在咱们本地开发 Dart 程序的话首先须要装置 Dart SDK。

官网文档:https://dart.dev/get-dart。

windows 环境

http://www.gekorm.com/dart-wi…。

mac 环境

参考上一篇文章, Mac 搭建 Flutter+Dart 开发环境。

3 开发工具

Dart 的开发工具有很多:IntelliJ IDEA、WebStorm、Atom、VS Code 等

这里咱们次要给大家解说的是如果在 VS Code 中配置 Dart。

1 装置 VS Code https://code.visualstudio.com/。

2 找到 VS Code 插件装置 dart。

3 找到 VS Code 插件装置 code runner Code Runner 能够运行咱们的文件。

4 变量 常量 命名规定

变量

dart 是一个弱小的脚本类语言,能够不事后定义变量类型,主动会类型推倒。

dart 中定义变量能够通过 var 关键字能够通过类型来申明变量。

留神:var 后就不要写类型,写了类型不要 var 两者都写 var a int = 5; 报错。

var str = 'this is var';
String str = 'this is var';
int str = 123;

常量

final 和 const 修饰符

const 值不变 一开始就得赋值。

final 能够开始不赋值 只能赋一次 ; 而 final 不仅有 const 的编译时常量的个性,最重要的它是运行时常量,并且 final 是惰性初始化,即在运行时第一次应用前才初始化。

永远不改量的量,请应用 final 或 const 润饰它,而不是应用 var 或其余变量类型。

final name = 'Bob'; // Without a type annotation
final String nickname = 'Bobby';
const bar = 1000000; // Unit of pressure (dynes/cm2)
const double atm = 1.01325 * bar; // Standard atmosphere

命名规定

1、变量名称必须由数字、字母、下划线和美元符 ($) 组成。

2、留神:标识符结尾不能是数字

3、标识符不能是保留字和关键字。

4、变量的名字是辨别大小写的如: age 和 Age 是不同的变量。在理论的使用中, 也倡议, 不要用一个单词大小写辨别两个变量。

5、标识符 (变量名称) 肯定要见名思意:变量名称倡议用名词,办法名称倡议用动词。

5 数据类型

罕用数据类型:

Numbers(数值)

int 必须是整型

double 既能够是整型 也可是浮点型

Strings(字符串)

String

字符串定义的几种形式

var str1 = 'this is str1';

var str2 = "this is str2";

String str1 = 'this is str1';

String str2 = "this is str2";

/// 三个 '''或者三个""" 能够多行
String str1 = '''
this is str1
this is str1
this is str1
''';

String str = """
this is str1
this is str1
this is str1
""";

字符串的拼接

String str1 = '你好';

String str2 = 'Dart';

print("$str1 $str2");

print(str1 + str2);

print(str1 +" "+ str2);

Booleans(布尔)

bool

List(数组)

在 Dart 中,数组是列表对象,所以大多数人只是称它们为列表

List 定义形式

var l1 = ['aaa','bbbb','cccc'];
var l2 = <String>[];

Maps(字典)

通常来说,Map 是一个键值对相干的对象。键和值能够是任何类型的对象。每个 键只呈现一次,而一个值则能够呈现屡次

Map 定义形式

var person = {
    "name":"张三",
    "age":20,
    "work":["程序员","送外卖"]
};
print(person["name"]);

var p = new Map();
p["name"] = "李四";
p["age"] = 22;
p["work"] = ["程序员","送外卖"];
print(p);

类型判断

var str=123;
if(str is String) {print('是 string 类型');
}
else if(str is int) {print('int');
} else {print('其余类型');
}

6 运算符 条件判断 类型转换

算术运算符

加减乘除取余取整

int a = 13;
int b = 5;
print(a + b);   // 加
print(a - b);   // 减
print(a * b);   // 乘
print(a / b);   // 除
print(a % b);   // 取余
print(a ~/ b);  // 取整

++ —

示意自增 自减 1

在赋值运算外面 如果 ++ — 写在后面 这时候先运算 再赋值,如果 ++ – 写在前面 先赋值后运行运算

var a = 10;
var b = a--;
print(a);  //9
print(b);  //10

var a = 10;
var b = ++a;
print(a);  //11
print(b);  //11

关系运算符

int a = 5;
int b = 3;
print(a == b);   // 判断是否相等
print(a != b);   // 判断是否不等
print(a > b);    // 判断是否大于
print(a < b);    // 判断是否小于
print(a >= b);   // 判断是否大于等于
print(a <= b);   // 判断是否小于等于

逻辑运算符

! 取反

bool flag = false;
print(!flag);

&& 并且: 全副为 true 的话值为 true 否则值为 false

bool a = true;
bool b = true;
print(a && b);

|| 或者:全为 false 的话值为 false 否则值为 true

bool a = false;
bool b = false;
print(a || b);

赋值运算符

根底赋值运算符 = ??=

int a = 10;
int b = 3;
print(a);
int c = a + b;   // 从右向左

int b;
b ??= 23;   // 示意如果 b 为空的话把 23 赋值给 b
print(b);

复合赋值运算符 += -= *= /= %= ~/=

var a = 13;
a += 10;   // 示意 a = a + 10
print(a);

条件表达式

if else switch case

// 判断一个人的问题 如果大于 60 显示及格   如果大于 70 显示良好  如果大于 90 显示优良
var score = 41;
if(score > 90) {print('优良');
} else if(score > 70) {print('良好');
} else if(score >= 60) {print('及格');
} else {print('不及格');
}

var sex = "女";
switch(sex) {
  case "男":
       print('性别是男');
       break;
  case "女":
       print('性别是女');
       break;
  default:
       print('传入参数谬误');
       break;
  }

三目运算符

bool flag = false;
String c = flag ? '我是 true' : '我是 false';
print(c);

?? 运算符

var a = 22;
var b = a ?? 10;
print(b);

类型转换

Number 与 String 类型之间的转换

Number 类型转换成 String 类型 toString()

String 类型转成 Number 类型 int.parse()

String str = '123';
var myNum = int.parse(str);
print(myNum is int);

String str = '123.1';
var myNum = double.parse(str);
print(myNum is double);

// 报错
String price = '';
var myNum = double.parse(price);
print(myNum);
print(myNum is double);

// try  ... catch
String price = '';
try {var myNum=double.parse(price);
    print(myNum);
} catch(err) {print(0);
} 

var myNum = 12;
var str = myNum.toString();
print(str is String);

其余类型转换成 Booleans 类型

isEmpty: 判断字符串是否为空

var str = '';
if(str.isEmpty) {print('str 空');
} else {print('str 不为空');
}

var myNum;
if(myNum == 0) {print('0');
} else {print('非 0');
}

var myNum;
if(myNum == null) {print('空');
} else {print('非空');
}

var myNum = 0/0;
print(myNum);
if(myNum.isNaN) {print('NaN');
}

7 循环遍历

for 循环

根本语法

第一步,申明变量 int i = 1;

第二步,判断 i <=100

第三步,print(i);

第四步,i++

第五步 从第二步再来,直到判断为 false

for (int i = 1; i <= 100; i++) {print(i);
}
 
// 打印 List  ['张三','李四','王五'] 外面的内容
var list = ['张三','李四','王五'];
for(var i = 0; i < list.length; i++) {print(list[i]);
}

while 循环

语法格局:

while(表达式 / 循环条件){

}

do{

语句 / 循环体

}while(表达式 / 循环条件);

留神:1、最初的分号不要遗记

2、循环条件中应用的变量须要通过初始化

3、循环体中,应有完结循环的条件,否则会造成死循环。

// 求 1 +2+3+4 ...+100 的和
int i = 1;
var sum = 0;
while(i <= 100) {
   sum += i;
   i++;
}
print(sum);

int i = 1;
var sum = 0;
do{
  sum += i;
  i++;
}while(i <= 100);
print(sum);

break 和 continue

break 语句性能:

1、在 switch 语句中使流程跳出 switch 构造。

2、在循环语句中使流程跳出以后循环, 遇到 break 循环终止,前面代码也不会执行

强调:

1、如果在循环中曾经执行了 break 语句, 就不会执行循环体中位于 break 后的语句。

2、在多层循环中, 一个 break 语句只能向外跳出一层

break 能够用在 switch case 中 也能够用在 for 循环和 while 循环中

continue 语句的性能:

【注】只能在循环语句中应用, 使本次循环完结,即跳过循环体重上面尚未执行的语句,接着进行下次的是否执行循环的判断。

continue 能够用在 for 循环以及 while 循环中,然而不倡议用在 while 循环中,不小心容易死循环

// 如果 i 等于 4 的话跳过
for(var i = 1; i <= 10; i++) {if(i == 4) {continue;  /* 跳过以后循环体 而后循环还会继续执行 */}
   print(i);
}
  
// 如果 i 等于 4 的话跳出循环
for(var i = 1; i <= 10; i++) {if(i == 4) {break;  /* 跳出循环体 */}
    print(i);
}

8 List

List 外面罕用的属性和办法:

罕用属性

length 长度

reversed 翻转

isEmpty 是否为空

isNotEmpty 是否不为空

var myList = ['香蕉','苹果','西瓜'];
print(myList.length);
print(myList.isEmpty);
print(myList.isNotEmpty);
print(myList.reversed);  // 对列表倒序排序
var newMyList = myList.reversed.toList();
print(newMyList);

罕用办法

add 减少

addAll 拼接数组

indexOf 查找 传入具体值

remove 删除 传入具体值

removeAt 删除 传入索引值

fillRange 批改

insert(index,value); 指定地位插入

insertAll(index,list) 指定地位插入 List

toList() 其余类型转换成 List

join() List 转换成字符串

split() 字符串转化成 List

forEach

map

where

any

every

// List 外面的办法:var myList = ['香蕉','苹果','西瓜'];
myList.add('桃子');   // 减少数据  减少一个
myList.addAll(['桃子','葡萄']);  // 拼接数组
print(myList);
print(myList.indexOf('苹 x 果'));    //indexOf 查找数据 查找不到返回 -1  查找到返回索引值
myList.remove('西瓜');
myList.removeAt(1);
print(myList);
  
var myList = ['香蕉','苹果','西瓜'];
myList.fillRange(1, 2, 'aaa');  // 批改
myList.fillRange(1, 3, 'aaa');  
myList.insert(1, 'aaa');      // 插入  一个
myList.insertAll(1, ['aaa', 'bbb']);  // 插入 多个
print(myList);

var myList = ['香蕉','苹果','西瓜'];
var str = myList.join('-');   //list 转换成字符串
print(str);
print(str is String);  //true

var str = '香蕉 - 苹果 - 西瓜';
var list = str.split('-');
print(list);
print(list is List);

9 Set

用它最次要的性能就是去除数组反复内容

Set 是没有程序且不能反复的汇合,所以不能通过索引去获取值

var s = new Set();
s.add('香蕉');
s.add('苹果');
s.add('苹果');
print(s);   // {香蕉, 苹果}
print(s.toList()); 

var myList = ['香蕉','苹果','西瓜','香蕉','苹果','香蕉','苹果'];
var s = new Set();
s.addAll(myList);
print(s);
print(s.toList());

10 Map

映射 (Map) 是无序的键值对:

罕用属性

keys 获取所有的 key 值

values 获取所有的 value 值

isEmpty 是否为空

isNotEmpty 是否不为空

Map person = {
    "name":"张三",
    "age":20
};

var m = new Map();
m["name"] = "李四";
print(person);
print(m);

Map person = {
    "name":"张三",
    "age":20,
    "sex":"男"
};
print(person.keys.toList());
print(person.values.toList());
print(person.isEmpty);
print(person.isNotEmpty);

罕用办法

remove(key) 删除指定 key 的数据

addAll({…}) 合并映射 给映射内减少属性

containsValue 查看映射内的值 返回 true/false

forEach

map

where

any

every

Map person = {
    "name":"张三",
    "age":20,
    "sex":"男"
};
person.addAll({"work":['敲代码', '送外卖'],
    "height":160
});
print(person);
person.remove("sex");
print(person);
print(person.containsValue('张三'));

11 forEach map where any every

forEach

List myList = ['香蕉', '苹果', '西瓜'];
for(var i = 0; i < myList.length; i++) {print(myList[i]);
}

for(var item in myList) {print(item);
}

myList.forEach((value) {print("$value");
});

var s = new Set();
s.addAll([1,222,333]);
s.forEach((value) => print(value));

Map person = {
    "name":"张三",
    "age":20
};
person.forEach((key,value){print("$key---$value");
});

map

List myList = [1, 3, 4];      
var newList = myList.map((value) {return value * 2;});
print(newList.toList());

where

List myList = [1, 3, 4, 5, 7, 8, 9];
var newList = myList.where((value) {return value > 5;});
print(newList.toList());

any

List myList = [1, 3, 4, 5, 7, 8, 9];
var f = myList.any((value) {   // 只有汇合外面有满足条件的就返回 true
     return value > 5;
});
print(f);

every

List myList = [1, 3, 4, 5, 7, 8, 9];
var f = myList.every((value) {   // 每一个都满足条件返回 true  否则返回 false
     return value > 5;
});
print(f);

12 办法的定义 变量 办法的作用域

内置办法 / 函数

print();

自定义办法

自定义办法的根本格局:

返回类型 办法名称(参数 1,参数 2,…){

办法体

return 返回值;

}

void printInfo(){print('我是一个自定义办法');
}

int getNum(){
  var myNum = 123;
  return myNum;
}

String printUserInfo(){return 'this is str';}

List getList(){return ['111','2222','333'];
}

void main(){print('调用零碎内置的办法');
  printInfo();
  
  var n = getNum();
  print(n);
  
  print(printUserInfo());
  print(getList());
  print(getList());
  

  // 演示办法的作用域
  void xxx(){aaa(){print(getList());
          print('aaa');
      }
      aaa();}

  // aaa();  谬误写法 
  xxx();  // 调用办法}

13 办法传参、可选参数、默认参数、命名参数、办法作为参数

办法传参

// 定义一个办法 求 1 到这个数的所有数的和      60    1+2+3+。。。+60
int sumNum(int n){
  var sum=0;
  for(var i = 1; i <= n; i++){sum+=i;}
  return sum;
} 
var n1 = sumNum(5);
print(n1);
var n2 = sumNum(100);
print(n2);

// 定义一个办法而后打印用户信息
String printUserInfo(String username, int age){  // 行参
  return "姓名:$username--- 年龄:$age";
}
print(printUserInfo('张三',20)); // 实参

可选参数

String printUserInfo(String username, [int age]){  // 行参
  if(age != null){return "姓名:$username--- 年龄:$age";}
  return "姓名:$username--- 年龄窃密";
}
print(printUserInfo('张三', 21)); // 实参
print(printUserInfo('张三'));

默认参数

String printUserInfo(String username, [String sex = '男', int age]){  // 行参
  if(age != null){return "姓名:$username--- 性别:$sex-- 年龄:$age";}
  return "姓名:$username--- 性别:$sex-- 年龄窃密";
}
print(printUserInfo('张三'));
print(printUserInfo('小李', '女'));
print(printUserInfo('小李', '女', 30));

命名参数

String printUserInfo(String username, {int age, String sex = '男'}){  // 行参
  if(age != null){return "姓名:$username--- 性别:$sex-- 年龄:$age";}
  return "姓名:$username--- 性别:$sex-- 年龄窃密";
}
print(printUserInfo('张三', age:20, sex:'未知'));

办法作为参数

var fn = () {print('我是一个匿名办法');
};      
fn();

// 办法
fn1(){print('fn1');
}

// 办法
fn2(fn){fn();
}

// 办法传参调用 fn2 这个办法 把 fn1 这个办法当做参数传入
fn2(fn1);

14 箭头函数 函数的互相调用

箭头函数

/* 需要:应用 forEach 打印上面 List 外面的数据 */
List list = ['苹果', '香蕉', '西瓜'];
list.forEach((value){print(value);
});

list.forEach((value) => print(value));

list.forEach((value) => {print(value)
});


/* 需要:批改上面 List 外面的数据,让数组中大于 2 的值乘以 2 */
List list = [4, 1, 2, 3, 4];
var newList = list.map((value){if(value > 2){return value * 2;}
  return value;
});
print(newList.toList());

var newList = list.map((value) => value > 2 ? value * 2 : value);
print(newList.toList());

函数的互相调用

/*
需要:1、定义一个办法 isEvenNumber 来判断一个数是否是偶数  
     2、定义一个办法打印 1 - n 以内的所有偶数
*/
// 定义一个办法 isEvenNumber 来判断一个数是否是偶数  
bool isEvenNumber(int n){if(n % 2 == 0){return true;}
  return false;
}

printNum(int n){for(var i = 1; i <= n; i++){if(isEvenNumber(i)){print(i);
    }
  }
}
printNum(10);

15 闭包

1、全局变量特点: 全局变量常驻内存、全局变量净化全局

2、局部变量的特点:不常驻内存会被垃圾机制回收、不会净化全局

想实现的性能:1. 常驻内存 2. 不净化全局

产生了闭包, 闭包能够解决这个问题 …..

闭包: 函数嵌套函数, 外部函数会调用内部函数的变量或参数, 变量或参数不会被零碎回收(不会开释内存)

闭包的写法:函数嵌套函数,并 return 外面的函数,这样就造成了闭包。

/* 全局变量 */
var a = 123;

void main(){print(a);
  fn(){
    a++;
    print(a);
  }
  fn();
  fn();
  fn();

  // 局部变量
  printInfo(){
    var myNum = 123;
    myNum++;
    print(myNum);
  }
  printInfo();
  printInfo();
  printInfo();
  
  // 闭包
  fn(){
    var a = 123;  /* 不会净化全局   常驻内存 */
    return(){            
      a++;            
      print(a);
     };        
  }     
  var b = fn();    
  b();
  b();
  b();}

16 面向对象的介绍 以及内置对象

面向对象编程 (OOP) 的三个基本特征

封装

封装是对象和类概念的次要个性。封装,把客观事物封装成形象的类,并且把本人的局部属性和办法提供给其余对象调用, 而一部分属性和办法则暗藏。

继承

面向对象编程 (OOP) 语言的一个次要性能就是“继承”。继承是指这样一种能力:它能够应用现有类的性能,并在无需从新编写原来的类的状况下对这些性能进行扩大。

多态

容许将子类类型的指针赋值给父类类型的指针, 同一个函数调用会有不同的执行成果。

Dart 所有的货色都是对象,所有的对象都继承自 Object 类。

Dart 是一门应用类和单继承的面向对象语言,所有的对象都是类的实例,并且所有的类都是 Object 的子类

一个类通常由属性和办法组成。

List list = new List();
list.isEmpty;
list.add('香蕉');
list.add('香蕉 1');

Map m = new Map();
m["username"] = "张三";
m.addAll({"age":20});
m.isEmpty;

Object a = 123;
Object v = true;
print(a);
print(v);

17 创立自定义类应用类

Dart 是一门应用类和单继承的面向对象语言,所有的对象都是类的实例,并且所有的类都是 Object 的子类

class Person {
  String name = "张三";
  int age = 23;
  void getInfo(){// print("$name----$age");
      print("${this.name}----${this.age}");
  }
  void setInfo(int age){this.age = age;}
}
void main(){

  // 实例化
  Person p1 = new Person();
  print(p1.name);
  p1.setInfo(28);
  p1.getInfo();}

自定义类的默认构造函数

class Person {
  String name = '张三';
  int age = 20; 
  
  // 默认构造函数
  Person(){print('这是构造函数外面的内容  这个办法在实例化的时候触发');
  }
  void printInfo(){print("${this.name}----${this.age}");
  }
}

// 张三  李四  王五
class Person {
  String name;
  int age; 
  
  // 默认构造函数
  Person(String name, int age){
    this.name = name;
    this.age = age;
  }
  void printInfo(){print("${this.name}----${this.age}");
  }
}

class Person {
  String name;
  int age; 
  
  // 默认构造函数的简写
  Person(this.name, this.age);
  void printInfo(){print("${this.name}----${this.age}");
  }
}

void main(){Person p1 = new Person('张三',20);
  p1.printInfo();

  Person p2 = new Person('李四',25);
  p2.printInfo();}

自定义类的命名构造函数

dart 外面构造函数能够写多个

class Person {
  String name;
  int age; 
  
  // 默认构造函数的简写
  Person(this.name, this.age);
  
  Person.now(){print('我是命名构造函数');
  }

  Person.setInfo(String name, int age){
    this.name = name;
    this.age = age;
  }

  void printInfo(){print("${this.name}----${this.age}");
  }
}

void main(){var d = new DateTime.now();   // 实例化 DateTime 调用它的命名构造函数
  print(d);
  
  Person p1 = new Person('张三', 20);   // 默认实例化类的时候调用的是 默认构造函数
  
  Person p1 = new Person.now();   // 命名构造函数
  
  Person p1 = new Person.setInfo('李四',30);
  p1.printInfo();}

把类独自抽离成一个模块

// 将 Person 类文件 Person.dart 放到 lib 文件夹外面
import 'lib/Person.dart';

void main(){Person p1 = new Person.setInfo('李四 1', 30);
  p1.printInfo();}

公有办法和公有属性

Dart 和其余面向对象语言不一样,Data 中没有 public private protected 这些拜访润饰合乎

咱们能够应用_把一个属性或者办法定义成公有。

class Animal {
  String _name;   // 公有属性
  int age; 
  
  // 默认构造函数的简写
  Animal(this._name, this.age);

  void printInfo(){print("${this._name}----${this.age}");
  }

  String getName(){return this._name;} 
  void _run(){print('这是一个公有办法');
  }

  execRun(){this._run();  // 类外面办法的互相调用
  }
}

import 'lib/Animal.dart';

void main(){Animal a = new Animal('小狗', 3);
 print(a.getName());
 a.execRun();   // 间接的调用公有办法}

类中的 getter 和 setter 修饰符的用法

class Rect {
  int height;
  int width;
  
  getArea(){return this.height * this.width;} 
}

class Rect {
  num height;
  num width; 
  
  Rect(this.height, this.width);
  area(){return this.height * this.width;}
}

void main(){Rect r = new Rect(10, 4);
  print("面积:${r.area()}");   
}

class Rect {
  num height;
  num width;   
  Rect(this.height, this.width);
  get area{return this.height * this.width;}
}

void main(){Rect r = new Rect(10, 2);
  print("面积:${r.area}");      // 留神调用间接通过拜访属性的形式拜访 area
}

class Rect {
  num height;
  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);
}

类中的初始化列表

咱们也能够在构造函数体运行之前初始化实例变量

class Rect {
  int height;
  int width;
  Rect():height = 2, width = 10{print("${this.height}---${this.width}");
  }
  getArea(){return this.height * this.width;} 
}

void main(){Rect r = new Rect();
  print(r.getArea()); 
}

类中的动态成员 静态方法

Dart 中的动态成员:

1、应用 static 关键字来实现类级别的变量和函数

2、静态方法不能拜访非动态成员,非静态方法能够拜访动态成员

class Person {
  static String name = '张三';
  static void show() {print(name);
  }
}

main(){print(Person.name);
  Person.show();}

class Person {
  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();}
}

main(){print(Person.name);
  Person.show(); 
  
  Person p = new Person();
  p.printInfo(); 
  Person.printUserInfo();}

对象操作符

? 条件运算符(理解)

as 类型转换

is 类型判断

.. 级联操作(连缀)(记住)

class Person {
  String name;
  num age;
  Person(this.name, this.age);
  void printInfo() {print("${this.name}---${this.age}");  
  }
}

main(){ 
  Person p;
  p?.printInfo();
  
  Person p = new Person('张三', 20);
  p?.printInfo();
  
  Person p = new Person('张三', 20);
  if(p is Person){p.name = "李四";} 
  p.printInfo();
  print(p is Object);

  var p1;
  p1 = '';
  p1 = new Person('张三 1', 20);

    // // p1.printInfo();
    // (p1 as Person).printInfo();

  Person p1 = new Person('张三 1', 20);
  p1.printInfo();
  p1.name = '张三 222';
  p1.age = 40;
  p1.printInfo();
  
  Person p1 = new Person('张三 1', 20);
  p1.printInfo();
  p1..name = "李四"
    ..age = 30
    ..printInfo();}

类的继承 - 简略继承

1、子类应用 extends 关键词来继承父类

2、子类会继承父类外面可见的属性和办法 然而不会继承构造函数

3、子类能复写父类的办法 getter 和 setter

class Person {
  String name = '张三';
  num age = 20; 
  void printInfo() {print("${this.name}---${this.age}");  
  } 
}

class Web extends Person {

}

main(){Web w = new Web();
  print(w.name);
  w.printInfo();}

super 关键词的应用

class Person {
  String name;
  num age; 
  Person(this.name, this.age);
  void printInfo() {print("${this.name}---${this.age}");  
  }
}

class Web extends Person {Web(String name, num age) : super(name, age){}}

main(){Person p = new Person('李四', 20);
  p.printInfo();

  Person p1 = new Person('张三', 20);
  p1.printInfo();

  Web w = new Web('张三', 12);
  w.printInfo();}

实例化自类 给父类构造函数传参

class Person {
  String name;
  num age; 
  Person(this.name, this.age);
  Person.xxx(this.name, this.age);
  void printInfo() {print("${this.name}---${this.age}");  
  }
}

class Web extends Person {
  String sex;
  Web(String name, num age, String sex) : super.xxx(name, age){this.sex = sex;}
  run(){print("${this.name}---${this.age}--${this.sex}");  
  }
}

main(){Person p = new Person('李四', 20);
  p.printInfo();
  
  Person p1 = new Person('张三', 20);
  p1.printInfo();

  Web w = new Web('张三', 12, "男");
  w.printInfo();
  w.run();}

实例化自类给命名构造函数传参

class Person {
  String name;
  num age; 
  Person(this.name, this.age);
  Person.xxx(this.name, this.age);
  void printInfo() {print("${this.name}---${this.age}");  
  }
}

class Web extends Person {
  String sex;
  Web(String name, num age, String sex) : super.xxx(name, age){this.sex = sex;}
  run(){print("${this.name}---${this.age}--${this.sex}");  
  }
}

main(){Person p = new Person('李四', 20);
  p.printInfo();
  
  Person p1 = new Person('张三', 20);
  p1.printInfo();

  Web w = new Web('张三', 12, "男");
  w.printInfo();
  w.run();}

覆写父类的办法

class Person {
  String name;
  num age; 
  Person(this.name, this.age);
  void printInfo() {print("${this.name}---${this.age}");  
  }
  work(){print("${this.name}在工作...");
  }
}

class Web extends Person {Web(String name, num age) : super(name, age);
  run(){print('run');
  }
  
  // 覆写父类的办法
  @override       // 能够写也能够不写  倡议在覆写父类办法的时候加上 @override 
  void printInfo(){print("姓名:${this.name}--- 年龄:${this.age}"); 
  }
  
  @override
  work(){print("${this.name}的工作是写代码");
  }
}

main(){Web w = new Web('李四', 20);
  w.printInfo();
  w.work();}

自类外面调用父类的办法

class Person {
  String name;
  num age; 
  Person(this.name, this.age);
  void printInfo() {print("${this.name}---${this.age}");  
  }
  work(){print("${this.name}在工作...");
  }
}

class Web extends Person {Web(String name, num age) : super(name, age);

  run(){print('run');
    super.work();  // 自类调用父类的办法}
  
  // 覆写父类的办法
  @override       // 能够写也能够不写  倡议在覆写父类办法的时候加上 @override 
  void printInfo(){print("姓名:${this.name}--- 年龄:${this.age}"); 
  }
}

main(){Web w = new Web('李四', 20);
  w.printInfo();
  w.run();}

抽象类

抽象类次要用于定义规范,子类能够继承抽象类,也能够实现抽象类接口。

1、抽象类通过 abstract 关键字来定义

2、形象办法不能用 abstract 申明,没有办法体的办法咱们称为形象办法。

3、如果子类继承抽象类必须得实现外面的形象办法

4、如果把抽象类当做接口实现的话必须得实现抽象类外面定义的所有属性和办法。

5、抽象类不能被实例化,只有继承它的子类能够

extends 抽象类 和 implements 的区别:

1、如果要复用抽象类外面的办法,并且要用形象办法束缚自类的话咱们就用 extends 继承抽象类

2、如果只是把抽象类当做规范的话咱们就用 implements 实现抽象类

案例:定义一个 Animal 类要求它的子类必须蕴含 eat 办法

abstract class Animal {eat();   // 形象办法
  run();   // 形象办法  
  printInfo(){print('我是一个抽象类外面的一般办法');
  }
}

class Dog extends Animal {
  @override
  eat() {print('小狗在吃骨头');
  }

  @override
  run() {print('小狗在跑');
  }  
}
class Cat extends Animal {
  @override
  eat() {print('小猫在吃老鼠');
  }

  @override
  run() {print('小猫在跑');
  }
}

main(){Dog d = new Dog();
  d.eat();
  d.printInfo();
  
  Cat c = new Cat();
  c.eat();
  c.printInfo();

  // Animal a=new Animal();   // 抽象类没法间接被实例化}

18 多态

容许将子类类型的指针赋值给父类类型的指针, 同一个函数调用会有不同的执行成果。

子类的实例赋值给父类的援用。

多态就是父类定义一个办法不去实现,让继承他的子类去实现,每个子类有不同的体现。

abstract class Animal {eat();   // 形象办法 
}

class Dog extends Animal {
  @override
  eat() {print('小狗在吃骨头');
  }
  run(){print('run');
  }
}

class Cat extends Animal {
  @override
  eat() {print('小猫在吃老鼠');
  }
  run(){print('run');
  }
}

main(){Dog d = new Dog();
  d.eat();
  d.run();

  Cat c = new Cat();
  c.eat();

  Animal d = new Dog();
  d.eat();

  Animal c = new Cat();
  c.eat();}

19 接口

和 Java 一样,dart 也有接口,然而和 Java 还是有区别的。

首先,dart 的接口没有 interface 关键字定义接口,而是一般类或抽象类都能够作为接口被实现。

同样应用 implements 关键字进行实现。

然而 dart 的接口有点奇怪,如果实现的类是一般类,会将一般类和形象中的属性和办法全副须要覆写一遍。

而因为抽象类能够定义形象办法,一般类不能够,所以个别如果要实现像 Java 接口那样的形式,个别会应用抽象类。

倡议应用抽象类定义接口。

定义一个 DB 库 反对 mysql mssql mongodb

mysql mssql mongodb 三个类外面都有同样的办法

abstract class Db {   // 当做接口   接口:就是约定、标准
    String uri;       // 数据库的链接地址
    add(String data);
    save();
    delete();}

class Mysql implements Db {
  
  @override
  String uri;

  Mysql(this.uri);

  @override
  add(data) {print('这是 mysql 的 add 办法'+data);
  }

  @override
  delete() {return null;}

  @override
  save() {return null;}

  remove() {}
}

class MsSql implements Db {
  @override
  String uri;
  @override
  add(String data) {print('这是 mssql 的 add 办法'+data);
  }

  @override
  delete() {return null;}

  @override
  save() {return null;}
}

main() {Mysql mysql = new Mysql('xxxxxx');
  mysql.add('1243214');
}

20 implements 实现多个接口

abstract class A {
  String name;
  printA();}

abstract class B {printB();
}

class C implements A, B {  
  @override
  String name; 
  
  @override
  printA() {print('printA');
  }
  
  @override
  printB() {return null;}
}

void main(){C c = new C();
  c.printA();}

21 mixins

mixins 的中文意思是混入,就是在类中混入其余性能。

能够应用 mixins 实现相似多继承的性能

因为 mixins 应用的条件,随着 Dart 版本始终在变,这里讲的是 Dart2.x 中应用 mixins 的条件:

1、作为 mixins 的类只能继承自 Object,不能继承其余类

2、作为 mixins 的类不能有构造函数

3、一个类能够 mixins 多个 mixins 类

4、mixins 绝不是继承,也不是接口,而是一种全新的个性

class A {
  String info = "this is A";
  void printA() {print("A");
  }
}

class B {void printB() {print("B");
  }
}

class C with A, B {

}

void main() {var c = new C();  
  c.printA();
  c.printB();
  print(c.info);
}

class Person {
  String name;
  num age;
  Person(this.name, this.age);
  printInfo() {print('${this.name}----${this.age}');
  }
  void run() {print("Person Run");
  }
}

class A {
  String info = "this is A";
  void printA() {print("A");
  }
  void run() {print("A Run");
  }
}

class B {void printB() {print("B");
  }
  void run() {print("B Run");
  }
}

class C extends Person with B, A {C(String name, num age) : super(name, age);
  
}

void main() {var c = new C('张三', 20);  
  c.printInfo();
  c.printB();
  print(c.info);
  c.run();}

mixins 的实例类型是什么?

很简略,mixins 的类型就是其超类的子类型。

class A {
  String info = "this is A";
  void printA() {print("A");
  }
}

class B {void printB() {print("B");
  }
}

class C with A, B { }

void main() {var c = new C();  
  print(c is C);    //true
  print(c is A);    //true
  print(c is B);    //true
  
  var a = new A();
  print(a is Object);
}

22 泛型

泛型就是解决 类 接口 办法的复用性、以及对不特定数据类型的反对(类型校验)

泛型办法

// 只能返回 string 类型的数据
String getData(String value) {return value;}
  
// 同时反对返回 string 类型 和 int 类型(代码冗余)String getData1(String value) {return value;}

int getData2(int value) {return value;}

// 同时返回 string 类型 和 number 类型       不指定类型能够解决这个问题
getData(value) {return value;}

// 不指定类型放弃了类型查看。咱们当初想实现的是传入什么 返回什么。比方: 传入 number 类型必须返回 number 类型  传入 string 类型必须返回 string 类型
getData<T>(T value) {return value;}

void main() {print(getData(21));
  print(getData('xxx'));
  getData<String>('你好');
  print(getData<int>(12));
}

汇合 List 泛型类的用法

案例:把上面类转换成泛型类,要求 List 外面能够减少 int 类型的数据,也能够减少 String 类型的数据。然而每次调用减少的类型要对立

class PrintClass<T> {List list = new List<T>();
      void add(T value){this.list.add(value);
      }
      void printInfo() {for(var i = 0; i < this.list.length; i++) {print(this.list[i]);
          }
      }
 }

main() {PrintClass p = new PrintClass<int>();
  p.add(12);
  p.add(23);
  p.printInfo();

  List list=new List<String>();
  // // list.add(12);  // 谬误的写法
  list.add('你好');
  list.add('你好 1');
  print(list);

  List list=new List<int>();
  // // list.add("你好");  // 谬误写法
  list.add(12); 
  print(list);
}

泛型接口

实现数据缓存的性能:有文件缓存、和内存缓存。内存缓存和文件缓存依照接口束缚实现。

1、定义一个泛型接口 束缚实现它的子类必须有 getByKey(key) 和 setByKey(key,value)

2、要求 setByKey 的时候的 value 的类型和实例化子类的时候指定的类型统一

abstract class Cache<T> {getByKey(String key);
  void setByKey(String key, T value);
}

class FlieCache<T> implements Cache<T> {
  @override
  getByKey(String key) {return null;}

  @override
  void setByKey(String key, T value) {print("我是文件缓存 把 key=${key}  value=${value}的数据写入到了文件中");
  }
}

class MemoryCache<T> implements Cache<T> {
  @override
  getByKey(String key) {return null;}

  @override
  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});
}

23 库

后面介绍 Dart 基础知识的时候基本上都是在一个文件外面编写 Dart 代码的,但理论开发中不可能这么写,模块化很重要,所以这就须要应用到库的概念。

在 Dart 中,库的应用时通过 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/pac…

https://pub.dartlang.org/flut…

1、须要在本人我的项目根目录新建一个 pubspec.yaml

2、在 pubspec.yaml 文件 而后配置名称、形容、依赖等信息

3、而后运行 pub get 获取包下载到本地

4、我的项目中引入库 import ‘package:http/http.dart’ as http; 看文档应用

导入本人本地库

import 'lib/Animal.dart';
main() {var a = new Animal('小黑狗', 20);
  print(a.getName());
}

导入零碎内置库

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();}

async 和 await

这两个关键字的应用只须要记住两点:

只有 async 办法能力应用 await 关键字调用办法

如果调用别的 async 办法必须应用 await 关键字

async 是让办法变成异步。

await 是期待异步办法执行实现。

void main() async {var result = await testAsync();
  print(result);

}

// 异步办法
testAsync() async{return 'Hello async';}

导入 Pub 包管理系统中的库

pub 包管理系统:

1、从上面网址找到要用的库

https://pub.dev/packages

https://pub.flutter-io.cn/pac…

https://pub.dartlang.org/flut…

2、创立一个 pubspec.yaml 文件,内容如下

name: xxx
description: A new flutter module project.
dependencies:
  http: ^0.12.0+2
  date_format: ^1.0.6

3、配置 dependencies

4、运行 pub get 获取近程库

5、看文档引入库应用

import 'dart:convert' as convert;
import 'package:http/http.dart' as http;
import 'package:date_format/date_format.dart';

main() async {
  var url = "http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20&page=1";
  
  // Await the http get response, then decode the json-formatted responce.
  var response = await http.get(url);
  if (response.statusCode == 200) {var jsonResponse = convert.jsonDecode(response.body);
    print(jsonResponse);
  } else {print("Request failed with status: ${response.statusCode}.");
  }
  print(formatDate(DateTime(1989, 2, 21), [yyyy, '*', mm, '*', dd]));
}

库的重命名 抵触解决

抵触解决

当引入两个库中有雷同名称标识符的时候,如果是 java 通常咱们通过写上残缺的包名门路来指定应用的具体标识符,甚至不必 import 都能够,然而 Dart 外面是必须 import 的。当抵触的时候,能够应用 as 关键字来指定库的前缀。如下例子所示:

import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;
Element element1 = new Element(); // Uses Element from lib1.
lib2.Element element2 = new lib2.Element(); // Uses Element from lib2.

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();}

局部导入

如果只须要导入库的一部分,有两种模式:

模式一:只导入须要的局部,应用 show 关键字,如下例子所示:

import 'package:lib1/lib1.dart' show foo;

模式二:暗藏不须要的局部,应用 hide 关键字,如下例子所示:

import 'package:lib2/lib2.dart' hide foo; 
//import 'lib/myMath.dart' show getAge;
import 'lib/myMath.dart' hide getName;

void main(){//  getName();
  getAge();}

提早加载

也称为懒加载,能够在须要的时候再进行加载。

懒加载的最大益处是能够缩小 APP 的启动工夫。

懒加载应用 deferred as 关键字来指定,如下例子所示:

当须要应用的时候,须要应用 loadLibrary()办法来加载:

import 'package:deferred/hello.dart' deferred as hello;
greet() async {await hello.loadLibrary();
  hello.printGreeting();}
正文完
 0