dart 介绍
Dart 是由谷歌开发的计算机编程语言,它可以被用于 web、服务器、移动应用 和物联网等领域的开发。
Dart 诞生于 2011 年,号称要取代 JavaScript。但是过去的几年中一直不温不火。直到 Flutter 的出现现在被人们重新重视。
dart 基础
Dart 变量
- dart 是一个强大的脚本类语言,可以不预先定义变量类型 ,自动会类型推倒
- dart 中定义变量可以通过 var关键字可以通过类型来申明变量
  var str='this is var';
  String str='this is var';
  int str=123;
// 注意: var 后就不要写类型 ,  写了类型 不要var   两者都写   var  a int  = 5;  报错
Dart 常量
- 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
Dart 的命名规则
- 变量名称必须由数字、字母、下划线和美元符($)组成。
- 注意:标识符开头不能是数字
- 标识符不能是保留字和关键字。
- 变量的名字是区分大小写的如: age 和 Age 是不同的变量。在实际的运用中,也建议,不要用一个单词大小写区分两个变量。
- 标识符(变量名称)一定要见名思意 :变量名称建议用名词,方法名称建议用动词 。
void main(){
    var str1='2134214';
    //var 2str='xxx';   //错误
    // var if='124214';  //错误
    //变量的名字是区分大小写的
    var age=20;
    var Age=30;
    print(age);
    print(Age);
    var price=12;
    var name=124;
}
入口方法
  main(){
    print('你好dart');
  }
数据类型
- 常用数据类型: - Number(数值),- int double
- String(字符串) ,- String
- Boolean(布尔),- bool
- List(数组): 在- Dart中,数组是列表对象,所以大多数人只是称它们为列表。
- Map(字典): 通常来说,- Map是一个键值对相关的对象。键和值可以是任何类型的对象。每个 键 只出现一次, 而一个值则可以出现多次。
 
- 项目中用不到的数据类型(用不到): - Runes:- Rune是- UTF-32编码的字符串。它可以通过文字转换成符号表情或者代表特定的文字。
- Symbols:- Symbol对象表示在- Dart程序中声明的运算符或标识符。您可能永远不需要使用符号,但它们对于按名称引用标识符的- API非常有用,因为缩小会更改标识符名称而不会更改标识符符号。要获取标识符的符号,请使用符号文字,它只是#后跟标识符。
 
String
void main(){
  //1、字符串定义的几种方式
  // var str1='this is str1';
  // var str2="this is str2";
  // print(str1);
  // print(str2);
  // String str1='this is str1';
  // String str2="this is str2";
  // print(str1);
  // print(str2);
  // String str1='''this is str1
  // this is str1
  // this is str1
  // ''';
  //  print(str1);
  //   String str1="""
  //   this is str1
  //   this is str1
  //   this is str1
  //   """;
  //  print(str1);
  //2、字符串的拼接
  String str1='你好';
  String str2='Dart';
  // print("$str1 $str2");
  print(str1 + str2);
  print(str1 +" "+ str2);
}
Number
void main(){
  //1、int   必须是整型
    int a=123;
    a=45;
    print(a);
  //2、double  既可以是整型 也可是浮点型
    double b=23.5;
    b=24;
    print(b);
  //3、运算符
  // + - * / %
    var c=a+b;
    print(c);
}
- Boolean
void main(){
  //1、bool
  // bool flag1=true;
  // print(flag1);
  // bool flag2=false;
  // print(flag2);
  //2、条件判断语句
  // var flag=true;
  // if(flag){
  //   print('真');
  // }else{
  //   print('假');
  // }
  // var a=123;
  // var b='123';
  // if(a==b){
  //   print('a=b');
  // }else{
  //    print('a!=b');
  // }
  var a=123;
  var b=123;
  if(a==b){
    print('a=b');
  }else{
      print('a!=b');
  }
}
List
void main() {
  //1、第一种定义List的方式
  // var l1=["张三",20,true];
  // print(l1);  //[张三, 20, true]
  // print(l1.length);  //3
  // print(l1[0]); //张三
  // print(l1[1]); //20
  //2、第二种定义List的方式 指定类型
  // var l2=<String>["张三","李四"];
  // print(l2);
  // var l3 = <int>[12, 30];
  // print(l3);
  //3、第三种定义List的方式  增加数据 ,通过[]创建的集合它的容量可以变化
  // var l4 = [];
  // print(l4);
  // print(l4.length);
  // l4.add("张三");
  // l4.add("李四");
  // l4.add(20);
  // print(l4);
  // print(l4.length);
  // var l5 = ["张三", 20, true];
  // l5.add("李四");
  // l5.add("zhaosi");
  // print(l5);
  //4、第四种定义List的方式
  //  var l6=new List();  //在新版本的dart里面没法使用这个方法了
  // var l6=List.filled(2, "");  //创建一个固定长度的集合
  // print(l6);
  // print(l6[0]);
  // l6[0]="张三";   //修改集合的内容
  // l6[1]="李四";
  // print(l6);  //[张三, 李四]
  // l6.add("王五");  //错误写法  通过List.filled创建的集合长度是固定  没法增加数据
  //通过List.filled创建的集合长度是固定
  // var l6=List.filled(2, "");
  // print(l6.length);
  // l6.length=0;  //修改集合的长度   报错
  // var l7=<String>["张三","李四"];
  // print(l7.length);  //2
  // l7.length=0;  //可以改变的
  // print(l7);  //[]
  var l8=List<String>.filled(2, "");
  l8[0]="string";
  // l8[0]=222;
  print(l8);
}
Map
void main(){
  //第一种定义 Maps的方式
  // var person={
  //   "name":"张三",
  //   "age":20,
  //   "work":["程序员","送外卖"]
  // };
  // print(person);
  // print(person["name"]);
  // print(person["age"]);
  // print(person["work"]);
  //第二种定义 Maps的方式
  var p=new Map();
  p["name"]="李四";
  p["age"]=22;
  p["work"]=["程序员","送外卖"];
  print(p);
  print(p["age"]);
}
判断数据类型
void main(){
  // var str='1234';
  // if(str is String){
  //   print('是string类型');
  // }else if(str is int){
  //    print('int');
  // }else{
  //    print('其他类型');
  // }
  var str=123;
  if(str is String){
    print('是string类型');
  }else if(str is int){
      print('int');
  }else{
      print('其他类型');
  }
}
运算,类型转换
算数符,条件判断语句
/*
1、Dart运算符:
    算术运算符
      +    -    *    /     ~/ (取整)     %(取余)
    关系运算符
      ==    !=   >    <    >=    <=
    逻辑运算符
        !  &&   ||
    赋值运算符
     基础赋值运算符   =   ??=
     复合赋值运算符   +=  -=  *=   /=   %=  ~/=
    条件表达式
        if  else   switch case
        三目运算符
        ??运算符:
2、类型转换
    1、Number与String类型之间的转换
    2、其他类型转换成Booleans类型
*/
算术运算
void main(){
  int a=13;
  int b=5;
  print(a+b);   //加
  print(a-b);   //减
  print(a*b);   //乘
  print(a/b);   //除
  print(a%b);   //其余
  print(a~/b);  //取整
  var c=a*b;
  print('--------');
  print(c);
}
关系运算
void main(){
  //  ==    !=   >    <    >=    <=
  int a=5;
  int b=3;
  print(a==b);   //判断是否相等
  print(a!=b);   //判断是否不等
  print(a>b);   //判断是否大于
  print(a<b);   //判断是否小于
  print(a>=b);   //判断是否大于等于
  print(a<=b);   //判断是否小于等于
  if(a>b){
    print('a大于b');
  }else{
    print('a小于b');
  }
}
逻辑运算
void main(){
  /* ! 取反 */
  // 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);
//如果一个人的年龄是20 并且 sex是女的话我们打印这个人
  // int age=20;
  // String sex="女";
  // if(age==20 && sex=="女"){
  //   print("$age --- $sex");
  // }else{
  //   print("不打印");
  // }
//如果一个人的年龄是20 或者 sex是女的话我们打印这个人
  int age=23;
  String sex="女";
  if(age==20 || sex=="女"){
    print("$age --- $sex");
  }else{
    print("不打印");
  }
}
赋值运算符
void main(){
//  1、基础赋值运算符   =   ??=
        // int a=10;
        // int b=3;
        // print(a);
        // int c=a+b;   //从右向左
    // b??=23;  表示如果b为空的话把 23赋值给b
        // int b=6;
        // b??=23;
        // print(b);
        // int b;
        // b??=23;
        // print(b);
//2、  复合赋值运算符   +=  -=  *=   /=   %=  ~/=
    // var a=12;
    // a=a+10;
    // print(a);
    // var a=13;
    // a+=10;   //表示a=a+10
    // print(a);
   var a=4;
   a*=3;  //a=a*3;
   print(a);
}
条件运算
void main(){
  //1、if  else   switch case
    // bool flag=true;
    // if(flag){
    //   print('true');
    // }else{
    //   print('false');
    // }
  //判断一个人的成绩 如果大于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('性别是女');
  //     print('性别是女');
  //     break;
  //   default:
  //     print('传入参数错误');
  //     break;
  // }
  //2、三目运算符
  // var falg=true;
  // var c;
  // if(falg){
  //     c='我是true';
  // }else{
  //   c="我是false";
  // }
  // print(c);
  bool flag=false;
  String c=flag?'我是true':'我是false';
  print(c);
  //3  ??运算符
  // var a;
  // var b= a ?? 10;
  // print(b);   10
  var a=22;
  var b= a ?? 10;
  print(b);
}
类型转换
void main(){
    //1、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='12';
      // var myNum=double.parse(price);
      // print(myNum);
      // 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);
 // 2、其他类型转换成Booleans类型
        // isEmpty:判断字符串是否为空
        // var str='';
        // if(str.isEmpty){
        //   print('str空');
        // }else{
        //   print('str不为空');
        // }
        // var myNum=123;
        // if(myNum==0){
        //    print('0');
        // }else{
        //   print('非0');
        // }
        // 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');
        }
}
dart 循环
- for循环
- while循环
- do while循环
- break和- continue
集合类型 List Set Map
List
/*
List里面常用的属性和方法:
    常用属性:
        length          长度
        reversed        翻转
        isEmpty         是否为空
        isNotEmpty      是否不为空
    常用方法:
        add         增加
        addAll      拼接数组
        indexOf     查找  传入具体值
        remove      删除  传入具体值
        removeAt    删除  传入索引值
        fillRange   修改
        insert(index,value);            指定位置插入
        insertAll(index,list)           指定位置插入List
        toList()    其他类型转换成List
        join()      List转换成字符串
        split()     字符串转化成List
        forEach
        map
        where
        any
        every
*/
void main(){
  // List myList=['香蕉','苹果','西瓜'];
  // print(myList[1]);
  // var list=new List();  //新版本没法使用
  // list.add('111');
  // list.add('222');
  // print(list);
//List里面的属性:
    // List myList=['香蕉','苹果','西瓜'];
    // print(myList.length);
    // print(myList.isEmpty);
    // print(myList.isNotEmpty);
    // print(myList.reversed);  //对列表倒序排序
    // var newMyList=myList.reversed.toList();
    // print(newMyList);
//List里面的方法:
    // List myList=['香蕉','苹果','西瓜'];
    //myList.add('桃子');   //增加数据  增加一个
    // myList.addAll(['桃子','葡萄']);  //拼接数组
    // print(myList);
    //print(myList.indexOf('苹x果'));    //indexOf查找数据 查找不到返回-1  查找到返回索引值
    // myList.remove('西瓜');
    // myList.removeAt(1);
    // print(myList);
    // List myList=['香蕉','苹果','西瓜'];
    // myList.fillRange(1, 2,'aaa');  //修改
    // myList.fillRange(1, 3,'aaa');
    // myList.insert(1,'aaa');      //插入  一个
    // myList.insertAll(1, ['aaa','bbb']);  //插入 多个
    // print(myList);
    // List 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);
}
Set
- 用它最主要的功能就是去除数组重复内容。
void main(){
  // var s=new Set();
  // s.add('香蕉');
  // s.add('苹果');
  // s.add('苹果');
  // print(s);   //{香蕉, 苹果}
  // print(s.toList());
  List myList=['香蕉','苹果','西瓜','香蕉','苹果','香蕉','苹果'];
  var s=new Set();
  s.addAll(myList);
  print(s);
  print(s.toList());
}
Map
/*
  映射(Maps)是无序的键值对:
    常用属性:
        keys            获取所有的key值
        values          获取所有的value值
        isEmpty         是否为空
        isNotEmpty      是否不为空
    常用方法:
        remove(key)     删除指定key的数据
        addAll({...})   合并映射  给映射内增加属性
        containsValue   查看映射内的值  返回true/false
        forEach
        map
        where
        any
        every
*/
void main(){
  // 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);
//常用方法:
    Map person={
      "name":"张三",
      "age":20,
      "sex":"男"
    };
    // person.addAll({
    //   "work":['敲代码','送外卖'],
    //   "height":160
    // });
    // print(person);
    // person.remove("sex");
    // print(person);
    print(person.containsValue('张三'));
}
forEach map where any every
void main(){
      //  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");
      // });
      // List myList=[1,3,4];
      // List newList=new List();
      // for(var i=0;i<myList.length;i++){
      //   newList.add(myList[i]*2);
      // }
      // print(newList);
      // List myList=[1,3,4];
      // var newList=myList.map((value){
      //     return value*2;
      // });
      // print(newList.toList());
      // List myList=[1,3,4,5,7,8,9];
      // var newList=myList.where((value){
      //     return value>5;
      // });
      // print(newList.toList());
      // List myList=[1,3,4,5,7,8,9];
      // var f=myList.any((value){   //只要集合里面有满足条件的就返回true
      //     return value>5;
      // });
      // print(f);
      // List myList=[1,3,4,5,7,8,9];
      // var f=myList.every((value){   //每一个都满足条件返回true  否则返回false
      //     return value>5;
      // });
      // print(f);
      // set
      // var s=new Set();
      // s.addAll([1,222,333]);
      // s.forEach((value)=>print(value));
      //map
       Map person={
          "name":"张三",
          "age":20
        };
        person.forEach((key,value){
            print("$key---$value");
        });
}
函数 (略)
函数高级应用
箭头函数
匿名方法,自执行方法
int getNum(int n) {
  return n;
}
void main() {
  // print(getNum(12));
  //匿名方法
  // var printNum=(){
  //   print(123);
  // };
  // printNum();
  // var printNum=(int n){
  //   print(n+2);
  // };
  // printNum(12);
//自执行方法
  // ((int n){
  //   print(n);
  //   print('我是自执行方法');
  // })(12);
//方法的递归
  // var sum = 1;
  // fn(int n) {
  //   sum *= n;
  //   if (n == 1) {
  //     return;
  //   }
  //   fn(n - 1);
  // }
  // fn(5);
  // print(sum);
//通过方法的递归 求1-100的和
  var sum=0;
  fn(int n){
      sum+=n;
      if(n==0){
        return;
      }
      fn(n-1);
  }
  fn(100);
  print(sum);
}
闭包
- 闭包: 函数嵌套函数, 内部函数会调用外部函数的变量或参数, 变量或参数不会被系统回收(不会释放内存)
- 闭包的写法: 函数嵌套函数,并 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(); // 124
  b(); // 125
  b(); // 126
}
类 对象
内置类
void main(){
    // List list=new List();  //最新版本的dart中已没法使用
    // 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);
}
自定义类
// 定义类
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(){
  //实例化
  // var p1=new Person();
  // print(p1.name);
  // p1.getInfo();
  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}");
//   }
// }
//最新版本的dart中需要初始化不可为null的实例字段,如果不初始化的话需要在属性前面加上late
// class Person{
//   late String name;
//   late int age;
//   //默认构造函数
//   Person(String name,int age){
//       this.name=name;
//       this.age=age;
//   }
//   void printInfo(){
//     print("${this.name}----${this.age}");
//   }
// }
//最新版本的dart中需要初始化不可为null的实例字段,如果不初始化的话需要在属性前面加上late
class Person{
  late String name;
  late 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里面构造函数可以写多个。
/*
注意:最新版本的dart中需要初始化不可为null的实例字段,如果不初始化的话需要在属性前面加上late
*/
class Person {
  late String name;
  late 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();
}
私有属性和私有方法
class Animal{
  late String _name;   //私有属性
  late 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();  //类里面方法的相互调用
  }
}
setter 与 getter
void main(){
    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);
  }
}
初始化
// Dart中我们也可以在构造函数体运行之前初始化实例变量
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());
}
静态成员, 静态方法
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();
}
Dart 中的对象操作符
- 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();   //已被最新的dart废弃 了解
  //  Person p=new Person('张三', 20);
  //  p?.printInfo();   //已被最新的dart废弃 了解
  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();
}
继承
- 简单继承 extends
- super关键字 继承
/*
面向对象的三大特性:封装 、继承、多态
Dart中的类的继承:
    1、子类使用extends关键词来继承父类
    2、子类会继承父类里面可见的属性和方法 但是不会继承构造函数
    3、子类能复写父类的方法 getter和setter
*/
class Person {
  late String name;
  late num age;
  late String gender;
  Person(this.name,this.age);
  void printInfo() {
    print("${this.name}---${this.age}");
  }
}
class Web extends Person{
  Web(String name, num age, String gender) : super(name, age){
    this.gender=gender;
  }
   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(); // 张三---12--男
}
复写父类的方法
- @override复写父类的方法
/*
面向对象的三大特性:封装 、继承、多态
Dart中的类的继承:
    1、子类使用extends关键词来继承父类
    2、子类会继承父类里面可见的属性和方法 但是不会继承构造函数
    3、子类能复写父类的方法 getter和setter
*/
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
  void printInfo(){
     print("姓名:${this.name}---年龄:${this.age}");
  }
  
  work(){
    print("${this.name}的工作是写代码");
  }
}
main(){
  Web w=new Web('李四',20);
  w.printInfo();
  w.work();
}
子类调用父类方法
- super关键字
/*
面向对象的三大特性:封装 、继承、多态
Dart中的类的继承:
    1、子类使用extends关键词来继承父类
    2、子类会继承父类里面可见的属性和方法 但是不会继承构造函数
    3、子类能复写父类的方法 getter和setter
*/
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
  void printInfo(){
     print("姓名:${this.name}---年龄:${this.age}");
  }
}
main(){
  Web w=new Web('李四',20);
  // w.printInfo();
  w.run();
}
抽象,多态,接口
抽象
- 关键字 abstract
abstract class Animal{
  eat();   //抽象方法
  run();  //抽象方法
  printInfo(){
    print('我是一个抽象类里面的普通方法');
  }
}
class Dog extends Animal{
  
  eat() {
     print('小狗在吃骨头');
  }
  
  run() {
    // TODO: implement run
    print('小狗在跑');
  }
}
class Cat extends Animal{
  
  eat() {
    // TODO: implement eat
    print('小猫在吃老鼠');
  }
  
  run() {
    // TODO: implement run
    print('小猫在跑');
  }
}
main(){
  Dog d=new Dog();
  d.eat();
  d.printInfo();
  Cat c=new Cat();
  c.eat();
  c.printInfo();
  // Animal a=new Animal();   //抽象类没法直接被实例化
}
多态
- 多态的实现,就是通过抽象类。多态就是父类定义一个方法不去实现,让继承他的子类去实现,每个子类有不同的表现。
abstract class Animal{
  eat();   //抽象方法
}
class Dog extends Animal{
  
  eat() {
     print('小狗在吃骨头');
  }
  run(){
    print('run');
  }
}
class Cat extends Animal{
  
  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(); // 小猫在吃老鼠
}
接口
- dart的接口没有- interface关键字定义接口,而是普通类或抽象类都可以作为接口被实现。
- 同样使用 - implements关键字进行实现。
/*
定义一个DB库 支持 mysql  mssql  mongodb
mysql  mssql  mongodb三个类里面都有同样的方法
*/
abstract class Db{   //当做接口   接口:就是约定 、规范
    late String uri;      //数据库的链接地址
    add(String data);
    save();
    delete();
}
class Mysql implements Db{
  
  String uri;
  Mysql(this.uri);
  
  add(data) {
    // TODO: implement add
    print('这是mysql的add方法'+data);
  }
  
  delete() {
    // TODO: implement delete
    return null;
  }
  
  save() {
    // TODO: implement save
    return null;
  }
  remove(){
  }
}
class MsSql implements Db{
  
  late String uri;
  
  add(String data) {
    print('这是mssql的add方法'+data);
  }
  
  delete() {
    // TODO: implement delete
    return null;
  }
  
  save() {
    // TODO: implement save
    return null;
  }
}
main() {
  Mysql mysql=new Mysql('xxxxxx');
  mysql.add('1243214');
}
mixins
一个类实现多个接口
- implements关键字
/*
Dart中一个类实现多个接口:
*/
abstract class A{
  late String name;
  printA();
}
abstract class B{
  printB();
}
class C implements A,B{
  
  late String name;
  
  printA() {
    print('printA');
  }
  
  printB() {
    // TODO: implement printB
    return null;
  }
}
void main(){
  C c=new C();
  c.printA();
}
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(); // A
  c.printB(); // B
  print(c.info); // this is A
}
多种类型的混入
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(); // B Run
}
泛型
泛型方法
  getData<T>(T value){
      return value;
  }
void main(){
    // print(getData(21));
    // print(getData('xxx'));
    // getData<String>('你好');
    print(getData<int>(12));
}
泛型类
class MyList<T> {
  List list = <T>[];
  void add(T value) {
    this.list.add(value);
  }
  List getList() {
    return list;
  }
}
main() {
  List list2 = new List<int>.filled(2, 0);
  list2[0] = 12;
  list2[1] = 13;
  print(list2);
}
泛型接口
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});
}
异步
 async 和 await
import 'dart:io';
getData() async {
  var result = await Future.delayed(Duration(seconds: 3), () {
    return "hello world";
  });
  return result;
}
main() {
  print("main start");
  getData();
  print("main end");
}
 Future 和 then
import 'dart:io';
main() {
  print("main start");
  // 2秒后执行的代码
  Future.delayed(Duration(seconds: 2), () {
    return "hello 111";
  }).then((data) {
    print(data);
  });
  // 3秒后执行的代码
  Future.delayed(Duration(seconds: 3), () {
    return "hello 222";
  }).then((data) {
    print(data);
  });
  print("main end");
}
库,系统库,第三方库
- Dart 中的库主要有三种: 
- 1、我们自定义的库 - import 'lib/xxx.dart';
 
- 2、系统内置库 - import 'dart:math';
- import 'dart:io';
- import 'dart:convert';
 
- 3、 - Pub包管理系统中的库- 1、需要在自己想项目根目录新建一个 - pubspec.yaml
- 2、在 - pubspec.yaml文件 然后配置名称 、描述、依赖等信息
- 3、然后运行 - pub get获取包下载到本地
- 4、项目中引入库 - import 'package:http/http.dart' as http;看文档使用
 
内置库
- 请求数据
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();
}
库名冲突解决
/*
1、冲突解决
当引入两个库中有相同名称标识符的时候,如果是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关键字来指定,如下例子所示:
    import 'package:deferred/hello.dart' deferred as hello;
    当需要使用的时候,需要使用loadLibrary()方法来加载:
    greet() async {
      await hello.loadLibrary();
      hello.printGreeting();
    }
*/
异常
/*
Dart中的异常处理
    1、on 捕获指定的异常
    2、catch 捕获所有的异常
    3、rethrow 重新抛出异常
    4、throw 用来抛出异常
*/
void main() {
  try {
    test();
  } on FormatException catch (e) {
    print('main()方法捕获了异常:$e');
  } catch (e) {
    print(e);
  } finally {
    print('finally');
  }
}
void test() {
  throw new FormatException('格式化异常');
}
dart 2.13 后 新特性
空安全
/*
  Null safety翻译成中文的意思是空安全。
  null safety 可以帮助开发者避免一些日常开发中很难被发现的错误,并且额外的好处是可以改善性能。
  Flutter2.2.0(2021年5月19日发布) 之后的版本都要求使用null safety。
  ? 可空类型
  ! 类型断言
*/
String? getData(apiUrl){
  if(apiUrl!=null){
    return "this is server data";
  }
  return null;
}
// void printLength(String? str){
//   // print(str!.length);
//   if (str!=null){
//     print(str.length);
//   }
// }
void printLength(String? str){
  try {
    print(str!.length);
  } catch (e) {
     print("str is null");
  }
}
void main(args) {
//1、 ? 可空类型
  // int a=123;
  // print(a);
  // String username="张三";
  // print(username);
  // List<String> l1=["张三","李四","王五"];
  // print(l1);
  // int a=123;  //非空的int类型
  // a=null;  //A value of type 'Null' can't be assigned to a variable of type 'int'
  // String username="张三";  //非空的String类型
  // username=null;   //A value of type 'Null' can't be assigned to a variable of type 'String'.
  // String? username="张三";   // String?  表示username是一个可空类型
  // username=null;
  // print(username);
  // int? a=123;  //  int? 表示a是一个可空类型
  // a=null;
  // print(a);
  // List<String> l1=["张三","李四","王五"];
  // l1=null;  //A value of type 'Null' can't be assigned to a variable of type 'List<String>'.
  // List<String>? l1=["张三","李四","王五"];
  // l1=null;
  // print(l1);
  //调用方法
  // print(getData("http://www.itying.com"));
  // print(getData(null));
//2. ! 类型断言
  // String? str="this is str";
  // str=null;
  // print(str!.length);
  //类型断言: 如果str不等于null 会打印str的长度,如果等于null会抛出异常
  //  printLength("str");
   printLength(null);
}
late 关键字
/*
Null safety翻译成中文的意思是空安全。
late 关键字主要用于延迟初始化。
*/
class Person {
  late String name;
  late int age;
  void setName(String name, int age) {
    this.name = name;
    this.age = age;
  }
  String getName() {
    return "${this.name}---${this.age}";
  }
}
void main(args) {
  Person p = new Person();
  p.setName("张三", 20);
  print(p.getName());
}
late 接口
/*
和Java一样,dart也有接口,但是和Java还是有区别的。
  首先,dart的接口没有interface关键字定义接口,而是普通类或抽象类都可以作为接口被实现。
  同样使用implements关键字进行实现。
  但是dart的接口有点奇怪,如果实现的类是普通类,会将普通类和抽象中的属性的方法全部需要覆写一遍。
  而因为抽象类可以定义抽象方法,普通类不可以,所以一般如果要实现像Java接口那样的方式,一般会使用抽象类。
  建议使用抽象类定义接口。
*/
/*
定义一个DB库 支持 mysql  mssql  mongodb
mysql  mssql  mongodb三个类里面都有同样的方法
*/
abstract class Db{   //当做接口   接口:就是约定 、规范
    late String uri; //数据库的链接地址
    add(String data);
    save();
    delete();
}
class Mysql implements Db{
  
  String uri;
  Mysql(this.uri);
  
  add(data) {
    // TODO: implement add
    print('这是mysql的add方法'+data);
  }
  
  delete() {
    // TODO: implement delete
    return null;
  }
  
  save() {
    // TODO: implement save
    return null;
  }
  remove(){
  }
}
class MsSql implements Db{
  
  late String uri;
  
  add(String data) {
    print('这是mssql的add方法'+data);
  }
  
  delete() {
    // TODO: implement delete
    return null;
  }
  
  save() {
    // TODO: implement save
    return null;
  }
}
main() {
  Mysql mysql=new Mysql('xxxxxx');
  mysql.add('1243214');
}
required 关键字
/*
required关键词:
    最开始 @required 是注解
    现在它已经作为内置修饰符。
    主要用于允许根据需要标记任何命名参数(函数或类),使得它们不为空。因为可选参数中必须有个 required 参数或者该参数有个默认值。
*/
String printUserInfo(String username, {int age=10, String sex="男"}) {//行参
  return "姓名:$username---性别:$sex--年龄:$age";
}
String printInfo(String username, {required int age, required String sex}) {//行参
  return "姓名:$username---性别:$sex--年龄:$age";
}
void main(args) {
    print(printUserInfo('张三'));
    print(printUserInfo('张三',age: 20,sex: "女"));
    //age 和 sex必须传入
    print(printInfo('张三',age: 22,sex: "女"));
}
required 命名参数
/*
required关键词:
    最开始 @required 是注解
    现在它已经作为内置修饰符。
    主要用于允许根据需要标记任何命名参数(函数或类),使得它们不为空。因为可选参数中必须有个 required 参数或者该参数有个默认值。
*/
//表示 name 和age 是必须传入的命名参数
class Person {
  String name;
  int age;
  Person({required this.name,required this.age});  //表示 name 和age 必须传入
  String getName() {
    return "${this.name}---${this.age}";
  }
}
void main(args) {
   Person p=new Person(
     name: "张三",
     age: 20
   );
   print(p.getName());
}
required 参数可选
/*
required关键词:
    最开始 @required 是注解
    现在它已经作为内置修饰符。
    主要用于允许根据需要标记任何命名参数(函数或类),使得它们不为空。因为可选参数中必须有个 required 参数或者该参数有个默认值。
*/
// name 可以传入也可以不传入   age必须传入
class Person {
  String? name;   //可空属性
  int age;
  Person({this.name,required this.age});  //表示 name 可以传入也可以不传入   age必须传入
  String getName() {
    return "${this.name}---${this.age}";
  }
}
void main(args) {
   Person p=new Person(
     name: "张三",
     age: 20
   );
   print(p.getName());  //张三---20
  Person p1=new Person(
     age: 20
   );
   print(p1.getName());  //null---20
}
普通构造函数和常量构造函数
- 普通构造函数
class Container{
  int width;
  int height;
  Container({required this.width,required this.height});
}
void main(){
  var c1=new Container(width: 100,height: 100);
  var c2=new Container(width: 100,height: 100);
  print( identical(c1, c2));  //false   c1和c2在内存中存储了2份
}
- 常量构造函数
/*
常量构造函数总结如下几点:
  1、常量构造函数需以const关键字修饰
  2、const构造函数必须用于成员变量都是final的类
  3、如果实例化时不加const修饰符,即使调用的是常量构造函数,实例化的对象也不是常量实例
  4、实例化常量构造函数的时候,多个地方创建这个对象,如果传入的值相同,只会保留一个对象。
  5、Flutter中const 修饰不仅仅是节省组件构建时的内存开销,Flutter 在需要重新构建组件的时候,由于这个组件是不应该改变的,重新构建没有任何意义,因此 Flutter 不会重建构建 const 组件
*/
//常量构造函数
class Container{
  final int width;
  final int height;
  const Container({required this.width,required this.height});
}
void main(){
  var c1=Container(width: 100,height: 100);
  var c2=Container(width: 100,height: 100);
  print(identical(c1, c2)); //false
  var c3=const Container(width: 100,height: 100);
  var c4=const Container(width: 100,height: 100);
  print(identical(c3, c4)); //true
  var c5=const Container(width: 100,height: 110);
  var c6=const Container(width: 120,height: 100);
  print(identical(c5, c6)); //false
}
// 实例化常量构造函数的时候,多个地方创建这个对象,如果传入的值相同,只会保留一个对象。
