dart语法

重温了下dart语法


基础

入口方法两种定义方式
main(){
  print('你好dart');
}
//加void表示方法没有返回值
void main(){
 print('你好dart');
}
命名规则
  • 变量名称必须由数字、字母、下划线和美元符($)组成。
  • 标识符开头不能是数字
  • 标识符不能是保留字和关键字
  • 变量的名字是区分大小写的如: age和Age是不同的变量。在实际的运用中,也建议,不要用一个单词大小写区分两个变量。
  • 变量名称建议用名词,方法名称建议用动词
定义变量

dart是一个强大的脚本类语言,可以不预先定义变量类型 ,自动会类型推倒

  • dart里面有类型校验
  • var后就不要写类型 ,写了类型不要var
var str='this is var';
String str='this is String';
int str=123;
定义变量

final 和 const修饰符 (永远不改量的量)

  • const值不变 一开始就得赋值
  • final 可以开始不赋值 只能赋一次 ; 而final不仅有const的编译时常量的特性,最重要的它是运行时常量,并且final是惰性初始化,即在运行时第一次使用前才初始化
//调用一个方法赋给一个常量就用final
final a=new DateTime.now();
print(a);   //2019-05-10 15:59:02.966122

//const a=new DateTime.now();   //报错了

数据类型

常用数据类型:

  • Numbers(数值): int (整型) double(浮点型)
  • Strings(字符串):String
  • Booleans(布尔):bool
  • List(数组):在Dart中,数组是列表对象,所以大多数人只是称它们为列表
  • Maps(字典):通常来说,Map 是一个键值对相关的对象。 键和值可以是任何类型的对象。每个 键 只出现一次, 而一个值则可以出现多次

项目中用不到的数据类型 (用不到):
Runes
Rune是UTF-32编码的字符串。它可以通过文字转换成符号表情或者代表特定的文字。

main() {
var clapping = ‘\u{1f44f}’;
print(clapping);
print(clapping.codeUnits);
print(clapping.runes.toList());

Runes input = new Runes(
    '\u2665  \u{1f605}  \u{1f60e}  \u{1f47b}  \u{1f596}  \u{1f44d}');
print(new String.fromCharCodes(input));

}

Symbols
Symbol对象表示在Dart程序中声明的运算符或标识符。您可能永远不需要使用符号,但它们对于按名称引用标识符的API非常有用,因为缩小会更改标识符名称而不会更改标识符符号。要获取标识符的符号,请使用符号文字,它只是#后跟标识符:

在 Dart 中符号用 # 开头来表示,入门阶段不需要了解这东西,可能永远也用不上。

http://dart.goodev.org/guides/libraries/library-tour#dartmirrors---reflection

字符串类型
 //1、字符串定义的几种方式
var str1='this is str1';
String str2='this is str1';

//三个单引号或多引号定义:可以写多行代码
String str1='''this is str1
 this is str1

this is str1
''';

String str1="""
 this is str1
 this is str1

  this is str1
  """;

  //2、字符串的拼接
  String str1='你好';
  String str2='Dart';
  print("$str1 $str2");
  print(str1 + str2);
  print(str1 +" "+ str2);
数值类型
  • int 必须是整型;
  • double 既可以是整型 也可是浮点型
//1、int   必须是整型
int a=123;
a=45;

//2、double  既可以是整型 也可是浮点型
double b=23.5;
b=24;
print(b);

//3、运算符    + - * / %
var c=a+b;

布尔类型

==不会对类型进行转换

//1、bool
bool flag1=true;
print(flag1);

 //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');
}
List(数组/集合)
//1、第一种定义List的方式
var l1=['aaa','bbbb','cccc'];
print(l1);
print(l1.length);
print(l1[1]);

//2、第二种定义List的方式
var l2=new List();
l2.add('张三');
l2.add('李四');
l2.add('王五');
print(l2);
print(l2[2]);


//3、定义List指定类型
var l3=new List<String>();
l3.add('张三');
l3.add(123); //报错
print(l3);
Maps(字典)

跟js的json对象有点相似

//第一种定义 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"]);
判断数据类型

is 关键词来判断类型

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

其它判断

//  isEmpty判断字符串是否为空
var str='';
if(str.isEmpty){
 print('str空');
}else{
 print('str不为空');
}

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

运算符

  • 算术运算符 + - * / ~/ (取整) %(取余)
  • 关系运算符 == !=(是否不等) > < >=(大于等于) <=(小于等于)
  • 逻辑运算符 ! && ||
  • 赋值运算符
  • 基础赋值运算符 = ??=
  • 复合赋值运算符 += -= *= /= %= ~/=
  • 条件表达式 if else switch case
  • 三目运算符
  • ??运算符
int age=23;
String sex="女";
if(age==20 || sex=="女"){
  print("$age --- $sex");
}else{
  print("不打印");
}

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

// ??运算符  
var a;
var b= a ?? 10;  a是为空的话就把10赋值给b
print(b);   10

类型转换

1、Number与String类型之间的转换

  • Number类型转换成String类型 toString()
  • String类型转成Number类型 int.parse() double.parse();
String str='123.1';
var myNum=double.parse(str);
print(myNum is double);

循环语句

for循环

for (int i = 1; i<=100; i++) {
print(i);
}

//第一步,声明变量int i = 1;
//第二步,判断i <=100
//第三步,print(i);
//第四步,i++
//第五步 从第二步再来,直到判断为false

  // 计算5的阶乘   (1*2*3*4*5    n的阶乘1*2……*n)
var sum=1;
for(var i=1;i<=5;i++){
  sum*=i;
}
print(sum);
while

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

do{
语句/循环体
}while(表达式/循环条件);

注意:
1、最后的分号不要忘记
2、循环条件中使用的变量需要经过初始化
3、循环体中,应有结束循环的条件,否则会造成死循环。

//while 和 do while的区别   第一次循环条件不成立的情况下
// int i=10;
// while(i<2){
// 	print('执行代码');
// }

var j=10;	  
do{
  print('执行代码');
}while(j<2);
++i和i++、break和continue

1、++ –
表示自增 自减 1
在赋值运算里面 如果++ – 写在前面 这时候先运算 再赋值,如果++ --写在后面 先赋值后运行运算
2、 break和continue
break语句功能:
1、在switch语句中使流程跳出switch结构。
2、在循环语句中使流程跳出当前循环,遇到break 循环终止,后面代码也不会执行
强调:
1、如果在循环中已经执行了break语句,就不会执行循环体中位于break后的语句。
2、在多层循环中,一个break语句只能向外跳出一层
break可以用在switch case中 也可以用在 for 循环和 while循环中

continue语句的功能:
【注】只能在循环语句中使用,使本次循环结束,即跳过循环体重下面尚未执行的语句,接着进行下次的是否执行循环的判断。
continue可以用在for循环以及 while循环中,但是不建议用在while循环中,不小心容易死循环

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

//2、如果 i等于4的话跳出循环
for(var i=1;i<=10;i++){
  if(i==4){
    break;  /*跳出循环体*/
  }
  print(i);
}

//3、break语句只能向外跳出一层
for(var i=0;i<5;i++){	 	
  print('外层---$i');
  for(var j=0;j<3;j++){	
    if(j==1){
      break;
    }
    print('里层$j');		 	
  }	
}

//4、while循环 break跳出循环
var i=1;
while(i<=10){
  if(i==4){
    break;
  }
  print(i);
  i++;
}

集合类型List Set Map详解

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

//定义list方法1
List myList=['香蕉','苹果','西瓜'];
print(myList[1]);

//定义list方法2
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.fillRange(1, 2,'aaa');  
myList.fillRange(1, 3,'aaa');  

//插入
myList.insert(1,'aaa');      //插入  一个
myList.insertAll(1, ['aaa','bbb']);  //插入 多个
print(myList);

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

//字符串转list
var str='香蕉-苹果-西瓜';
var list=str.split('-');
print(list);
print(list is List);
Set
  • 用它最主要的功能就是去除数组重复内容
  • Set是没有顺序且不能重复的集合,所以不能通过索引去获取值
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());
Maps

常用属性:

keys获取所有的key值
values获取所有的value值
isEmpty是否为空
isNotEmpty是否不为空

常用方法:

remove(key)删除指定key的数据
addAll({…})合并映射 给映射内增加属性
containsValue查看映射内的值 返回true/false
forEach
map
where
any
every
//定义方法1
Map person={
  "name":"张三",
  "age":20
};

//定义方法2
var m=new Map();
m["name"]="李四";


//常用属性:
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
});
person.remove("sex");
print(person.containsValue('张三'));

函数

内置方法/函数: 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'];
}
//1、定义一个方法然后打印用户信息
String printUserInfo(String username,int age){  //行参
  return "姓名:$username---年龄:$age";
}
print(printUserInfo('张三',20)); //实参


//2、定义一个带可选参数的方法
String printUserInfo(String username,[int age]){  //行参
if(age!=null){
return "姓名:$username---年龄:$age";
}
return "姓名:$username---年龄保密";
}
print(printUserInfo('张三',21)); //实参
print(printUserInfo('张三'));


//3、定义一个带默认参数的方法
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));


//4、定义一个命名参数的方法
String printUserInfo(String username,{int age,String sex='男'}){  //行参
    if(age!=null){
      return "姓名:$username---性别:$sex--年龄:$age";
    }
    return "姓名:$username---性别:$sex--年龄保密";
}
print(printUserInfo('张三',age:20,sex:'未知'));


//5、实现一个 把方法当做参数的方法
var fn=(){
  print('我是一个匿名方法');
};      
fn();


//6、把fn方法当做参数传入
//方法
fn1(){
  print('fn1');
}
//方法
fn2(fn){
  
  fn();
}
//调用fn2这个方法 把fn1这个方法当做参数传入
fn2(fn1);
匿名方法、自执行方法
//匿名方法
var printNum=(){
  print(123);
};
printNum();

var printNum=(int n){
  print(n+2);
};
printNum(12);

//自执行方法
((int n){
  print(n);
  print('我是自执行方法');
})(12);
//方法的递归
var sum=1;			
fn(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);
闭包

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

  • 常驻内存
  • 不污染全局

闭包: 函数嵌套函数, 内部函数会调用外部函数的变量或参数, 变量或参数不会被系统回收(不会释放内存)
闭包的写法: 函数嵌套函数,并return 里面的函数,这样就形成了闭包。

fn(){
  var a=123;  /*不会污染全局   常驻内存*/
  return(){			
    a++;			
    print(a);
  };        
}     
var b=fn();	
b();

对象 类

面向对象编程(OOP)的三个基本特征是:封装、继承、多态

  • 封装:封装是对象和类概念的主要特性。封装,把客观事物封装成抽象的类,并且把自己的部分属性和方法提供给其他对象调用, 而一部分属性和方法则隐藏。
  • 继承:面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
  • 多态:允许将子类类型的指针赋值给父类类型的指针, 同一个函数调用会有不同的执行效果 。

Dart所有的东西都是对象,所有的对象都继承自Object类()。(所有的对象都是类的实例)
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(){
  //实例化
  // 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; 
  //默认构造函数的简写
  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(); 

}
把类单独抽离成一个模块
import 'lib/Person.dart';

void main(){
  Person p1=new Person.setInfo('李四1',30);
  p1.printInfo(); 
}
私有方法和私有属性

Dart和其他面向对象语言不一样,Data中没有 public private protected这些访问修饰符合
但是我们可以使用_把一个属性或者方法定义成私有。

// lib/Animal.dart
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();  //类里面方法的相互调用
  }
}

// main.dart
import 'lib/Animal.dart';
void main(){
 Animal a=new Animal('小狗', 3);
 print(a.getName());
  a.execRun();   //间接的调用私有方法
}
getter和setter修饰符的用法
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);
}

#####初始化列表

// 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(){ 

//1、条件运算符 ?
Person p;
p?.printInfo(); //如果p是空对象,则不会调用方法,也不会报错

Person p=new Person('张三', 20);
p?.printInfo(); //p不是空对象,则会调用方法


//2、类型判断 is
Person p=new Person('张三', 20);
if(p is Person){ //判断p是否属于Person类型
  p.name="李四";
} 
p.printInfo();
print(p is Object);
    

//3、类型转换 as
var p1;
p1='';
p1=new Person('张三1', 20);
p1.printInfo(); //报错
(p1 as Person).printInfo(); 

    


//4、级联操作 ...
// 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();
  
}

类的继承-简单继承

面向对象的三大特性:封装 、继承、多态
Dart中的类的继承:
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();
}
类的继承-实例化自类给父类构造函数传参
class Person {
  String name;
  num age; 
  Person(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(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); //xxx表示命名构造函数
  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(" t h i s . n a m e − − − {this.name}--- 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(“姓名: t h i s . n a m e − − − 年 龄 : {this.name}---年龄: this.name{this.age}”);
}

}

main(){
Web w=new Web(‘李四’,20);
// w.printInfo();
w.run();
}
···

抽象类、多态以及接口

抽象类

Dart中抽象类: Dart抽象类主要用于定义标准,子类可以继承抽象类,也可以实现抽象类接口。
1、抽象类通过abstract 关键字来定义
2、Dart中的抽象方法不能用abstract声明,Dart中没有方法体的方法我们称为抽象方法。
3、如果子类继承抽象类必须得实现里面的抽象方法
4、如果把抽象类当做接口实现的话必须得实现抽象类里面定义的所有属性和方法。
5、抽象类不能被实例化,只有继承它的子类可以

extends抽象类 和 implements的区别:
1、如果要复用抽象类里面的方法,并且要用抽象方法约束自类的话我们就用extends继承抽象类
2、如果只是把抽象类当做标准的话我们就用implements实现抽象类

// 定义一个Animal 类要求它的子类必须包含eat方法
abstract class Animal{ //加abstract  
  eat();  //把eat定义成抽象方法,所有子类都有eat方法
  run();  //抽象方法  
  printInfo(){
    print('我是一个抽象类里面的普通方法');
  }
}

class Dog extends Animal{
  @override
  eat() { //抽象类用来约束子类,必须有eat()抽象方法,否则报错
     print('小狗在吃骨头');
  }

  @override
  run() {
    // TODO: implement run
    print('小狗在跑');
  }  
}

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

  @override
  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();   //抽象类没法直接被实例化
}
多态

Datr中的多态:
允许将子类类型的指针赋值给父类类型的指针, 同一个函数调用会有不同的执行效果 。
子类的实例赋值给父类的引用。
多态就是父类定义一个方法不去实现,让继承他的子类去实现,每个子类有不同的表现。

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(); //把子类的实类赋值给Animal父类的引用,这样就没有run方法
  d.eat();

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

和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) {
    // TODO: implement add
    print('这是mysql的add方法'+data);
  }

  @override
  delete() {
    // TODO: implement delete
    return null;
  }

  @override
  save() {
    // TODO: implement save
    return null;
  }

  remove(){
  }
}

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

  @override
  delete() {
    // TODO: implement delete
    return null;
  }

  @override
  save() {
    // TODO: implement save
    return null;
  }
}

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

接口 文件分离

// import 'lib/Mysql.dart';
import 'lib/MsSql.dart';
main() {
  // Mysql mysql=new Mysql('xxxxxx');
  // mysql.add('1243214');
  MsSql mssql=new MsSql();
  mssql.uri='127.0.0.1';
  mssql.add('增加的数据');
}

一个类实现多个接口 以及Dart中的Mixins

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() {
    // TODO: implement printB
    return null;
  }
}


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

mixins的中文意思是混入,就是在类中混入其他功能。
在Dart中可以使用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{ //具有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 { //不能 extends Person,否则无法作为mixins的类
  // 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的类型
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); //true 所有的类都继承object的类
}

泛型

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

泛型方法
//不指定类型放弃了类型检查。我们现在想实现的是传入什么 返回什么。比如:传入number 类型必须返回number类型  传入 string类型必须返回string类型
 
//前面加T是对返回类型作校验  后面的是对传入参数进行校验
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)); //没有校验
}
泛型类

把下面类转换成泛型类,要求List里面可以增加int类型的数据,也可以增加String类型的数据。但是每次调用增加的类型要统一

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

PrintClass p=new PrintClass();
p.add(1);
p.add(12);
p.add(5);
p.printInfo();


// 把类转换成泛型类
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();
}
泛型接口

实现数据缓存的功能:有文件缓存、和内存缓存。内存缓存和文件缓存按照接口约束实现。
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});
}

在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/packages
https://pub.dartlang.org/flutter/

1、需要在自己想项目根目录新建一个pubspec.yaml
2、在pubspec.yaml文件 然后配置名称 、描述、依赖等信息
3、然后运行 pub get 获取包下载到本地  
4、项目中引入库 import 'package:http/http.dart' as http; 看文档使用
导入库
//1、导入自己本地库
import 'lib/Animal.dart';
main(){
  var a=new Animal('小黑狗', 20);
  print(a.getName());
}

//2、导入系统内置库 math库
import "dart:math";
main(){
  print(min(12,23));
  print(max(12,25));
}
请求数据httpClient

导入系统内置库实现请求数据httpClient

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/packages
https://pub.dartlang.org/flutter/

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、看文档引入库使用

重命名 Dart冲突解决

1、冲突解决
当引入两个库中有相同名称标识符的时候,如果是java通常我们通过写上完整的包名路径来指定使用的具体标识符,甚至不用import都可以,但是Dart里面是必须import的。当冲突的时候,可以使用as关键字来指定库的前缀。如下例子所示:

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();
}
  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值