俗话说 ‘工欲善其事必先利其器’ 想要撸flutter app 而不懂 dart 那就像一个不会英语的人在和英国人交流,懵!

安装 dart 就不用说了,比较简单dart 官网 https://dart.dev/

安装完成后就开启学习dart 旅程吧…

一、 首先得找个ide (总不能使用记事本撸吧),所以我们选择 idea 这个开发不错

1)idea 安装 dart (简单同直接 打开idea configure > plugins )



二、 创建一个项目开始 学习语法了



这里的dart-sdk 在dart官网直接下载就行,然后创建一个dart项目

void main(){
print("hello world! ");
}

程序入口 main() 这就是java 风格

三、 数据类型

3.1 dart 变量

var :变量(任何类型)

const : 常量

final : 变量(只能赋值一次)

3.2 内置 类型

Number:数值型

String:字符串

Boolean:布尔型

List:列表

Map:键值对

另外还有 Runes 和Symbols 类型

定义数值型使用 num关键字 ,他主要包括 整形 int 和浮点型 double (这个就比java中的八大基本类型简单多了)

代码案例:

void main(){
var name = 'dex'; const age = 22;
final addr = "china"; num a = 10; a = 12.5; int b = 20; double c = 10.5; print(c);
}

注意:每一行都要以 ; 结尾

3.3 数值型操作

1) 运算符 : + 、- 、* 、/ 、~/ 、%

其他都不用说和java 或者js都是相同的运用,唯有 ~/ : 是标识取余

2)常量属性:isNaN (是否非数字)、isEven(是否偶数)、isOdd(是否奇数)

3)常用方法:abs() (取绝对值)、round() (四舍五入)、floor() (向下取整【不大于基数】) 、ceil()(向上取整【不小于基数】)、toInt()、toDouble()

void main(){
int age = 40;
double score = 80.9;
int grade = -5; print(score / age); // 2.0225
print(score % age); // 0.9000000000000057
print(score ~/ age); // 2 print(score.floor()); // 80
print(score.ceil()); // 81
print(score.round()); // 81
print(grade.abs()); // 5 print(age.isEven); // true
print(age.isOdd); // false
print(age.isNaN); // false
}

3.4 字符串(String)

定义String 使用单引号、双引号、三个引号来定义字符串和 r 来创建原始的raw字符串

void main(){
String article = ''' Hello welcome to
dart develope ceter''';
print(article); // Hello welcome to
// dart develope ceter // use r operator
String caption = r" Hello \n Lilei !";
print(caption); // Hello \n Lilei !
}

字符串操作符 : + (字符拼接) 、* (字符按参数累加)、 == (字符比对)、 [](按下标获取数据)

void main(){
String str = "This is my first proj"; print(str * 5); // This is my first projThis is my first projThis is my first projThis is my first projThis is my first proj print(str[5]); // i
}

插值表达式 ${expression}

void main(){
String name = 'jack';
int age = 20;
String addr = '四川成都'; String information = '$name今年$age岁 来自${addr}' ;
print(information); // jack今年20岁 来自四川成都
}

常用属性: length 、isEmpty 、isNotEmpty

常用方法:contains() 、subString() 、startsWith()、 endsWith() 、indexOf() 、lastIndexOf() 、toLowerCase() 、toUpperCase() 、trim() 、trimLeft() 、trimRight()、 split()、 replaceAll()、replaceFirst() … 这些同java中的Sting方法使用是相同的,这里就不累诉了

3.5 布尔型 bool

void main(){
bool isNice = true;
print(isNice); // true
}

3.6 List 列表/ 数组 (list 元素可以任意类型)

创建语法:

var list = [1,2,3,4,5,6];  // 普通list 创建
var list = const[1,2,3,4,5,6]; // 创建一个不可变list
var list = new List(); // 使用构造创建
void main(){
var studentList = [1,2,3 ,"hello dart",true]; print(studentList); // [1, 2, 3, hello dart, true] print(studentList[2]); // 3
studentList[1] = 'Lilei'; print(studentList); // [1, Lilei, 3, hello dart, true] var teacherList = new List();
teacherList[0] = 'Macke'; // Unhandled exception: RangeError (index): Invalid value: Valid value range is empty: 0 (因为这个teacherList对象只有创建了,但还未开辟内存空间)
teacherList.add( 'Macke');
print(teacherList); // [Macke]
}

常用方法:[] 、length、 add()、 insert() 、remove() 、clear() 、indexOf()、 lastIndexOf() 、sort() 、sublist() 、shuffle()、 asMap() forEach() …

void main(){
var hobbies = ["jog","swim","red"];
hobbies.insert(1,"tourism");
print(hobbies); // [jog, tourism, swim, red] print(hobbies.indexOf("tourism")); // 1 hobbies.sort(); print(hobbies); // [jog, red, swim, tourism] print(hobbies.sublist(1)); // [red, swim, tourism] hobbies.shuffle(); // 打乱元素
print(hobbies); // [jog, tourism, red, swim] hobbies.forEach(print);// jog
// tourism
// red
// swim
}

3.7 Map (key-val可以任何类型)

语法:

var studyPlan = {'first':'Dart','second':'Flutter'}; // 创建普通map
var studyPlan = const{'first':'Dart','second':'Flutter'}; // 创建一个不可变map
var studyPlan = new Map(); // 使用构造函数创建
void main(){
var studyPlan = {'first':'Dart','second':'Flutter','isHappy':true,true:'ok'}; print(studyPlan); // {first: Dart, second: Flutter, isHappy: true, true: ok} print(studyPlan['first']); // Dart
print(studyPlan[true]);// ok
studyPlan[2] = false;
print(studyPlan); // {first: Dart, second: Flutter, isHappy: true, true: ok, 2: false}
}

常用方法: []、 length、 isEmpty()、 isNotEmpty() 、Keys、 values containsKey()、 containsValue() 、remove()、 forEach()…

void main(){
var studyPlan = {'first':'Dart','second':'Flutter','isHappy':true,true:'ok'}; print(studyPlan.keys); // (first, second, isHappy, true)
print(studyPlan.values); // (Dart, Flutter, true, ok)
print(studyPlan.containsKey('first')); // true
print(studyPlan.containsValue('Dart')); // true
studyPlan.remove('isHappy');
print(studyPlan); // {first: Dart, second: Flutter, true: ok} // 调用自定义proxyPrint方法进行map
studyPlan.forEach(proxyPrint);// key=first,value = Dart
// key=second,value = Flutter
// key=true,value = ok var list = ['lili','lulu','xinxin'];
// asMap() 将使用下标作为key ,元素作为val然后将其转换为map对象
print(list.asMap()); // {0: lili, 1: lulu, 2: xinxin}
} void proxyPrint(key,value){
print("key=$key,value = $value");
}

3.8 dynamic (动态类型【根据值自动更改变量类型】)

void main(){
dynamic nickname = '小鱼儿';
print(nickname); // 小鱼儿
nickname = '雷震子';
print(nickname); // 雷震子 // 定义类型为泛型的list
var generic = new List<dynamic>();
generic.add(6);
generic.add(8.8);
generic.add('hello');
generic.add(true);
print(generic); // [6, 8.8, hello, true]
}

四、运算符

4.1 运算符

其中 + 、-、 *、 / 、||、 !、 && 、++、 – 、+=、-=、*=…这些同java 一样使用,其中特殊的赋值运算符中的 ??= (表示 变量如果原本无值及将右边值赋值于变量,如果变量原本有值就使用它原本的值)

void main(){
int time = 12;
int hour = 10; hour ??= 18;
print(hour); // 10 int second ;
second ??= 60;
print(second); // 60
}

还有一个不同的是复合运算中的 ~/(取整)

void main(){
int time = 122;
int hour = 10;
print(time ~/ hour); // 12
}

4.2 条件表达式

1) 三目运算符: condition ? expression1 : expression2

2 ) ??运算符 expression1 ?? expression2 (如果expression1 不为空则取其值,反之取expression2的值)

  void main(){
String goods = "apple";
String toolLearn;
String bag = goods ?? toolLearn; print(bag); // apple String grocery ;
String shop = "boxes";
String backpack = grocery ?? shop; print(backpack); // boxes }

五、 控制语句

if…elseif…elseif…else这个和java控制语句相同 ,唯一一个不同的是switch … case 中可以使用continue 跳转到指定语句

void main(){
String myHobby = "jog"; switch(myHobby){
case "game":
print("my hobby is game");
break;
case "jog":
print("my hobby is jog");
continue Prefer;
case "red":
print("my hobby is red");
break;
Prefer:
default:
print("I like study different languages, haha!");
}
// print out :
// my hobby is jog
// I like study different languages, haha!
}

六、 Function (方法)

6.1 方法定义

语法

返回值类型  方法名 (参数1、参数2...){
方法体...
return 返回值
}

这个同java 使用方式一样,不同的是他叫function 而不是 method ,还有个不同的是形参可以指定类型也可以不指定,这个有和JavaScript 的函数有定类似了

void main(){
String info = getPersonInfo('Lili','18'); // error: The argument type 'String' can't be assigned to the parameter type 'int'.
print(info);
} String getPersonInfo (String name,int age){
return "This girl's name is $name,she is $age years old";
}

如上你如果调用时参数类型不同就无法编译通过

void main(){
String info = getPersonInfo('Lili','18');
print(info); // This girl's name is Lili,she is 18 years old
} String getPersonInfo ( name, age){
return "This girl's name is $name,she is $age years old";
}

不指定参数类型也是被允许的

方法特性

1) 方法也是一个对象,并且具有具体类型 Function

2)返回值类型、参数类型都可以省略

3)箭头语法:=> expr{ return expr;} 的缩写 ,但是只适用于一个表达式

4)方法都有返回值。如果没有显示指定;它默认会在方法最后 return null

void main(){
String info = getPersonInfo('Lili',18);
print(info); // This girl's name is Lili,she is 18 years old
} /*
方法 getPersonInfo 的完整写法
String getPersonInfo(Sting name, int age){
return "This girl's name is $name,she is $age years old";
}
*/
getPersonInfo ( name, age) => "This girl's name is $name,she is $age years old";

哈哈 对js 熟悉的小伙伴看见这个箭头语法是不是感觉特亲切呢!

6.2 方法中的可选参数

1)可选命名参数:{parm1, param2, …}

2)可选位置参数:[parm1,param2, …]

可选的命名参数在调用时必须加上参数名进行实参传递如:

void main(){
getPersonInfo('Lili'); // This girl's name is Lili, she is null years old and she lives in null
getPersonInfo('Lili',age: 18); // This girl's name is Lili, she is 18 years old and she lives in null
getPersonInfo('Lili',age: 18,addr: 'Chengdu, Sichuan, China'); // This girl's name is Lili, she is 18 years old and she lives in Chengdu, Sichuan, China
}
getPersonInfo ( String name, {int age ,String addr}) => print("This girl's name is $name, she is $age years old and she lives in $addr ");

看过了可选命名参数,可选位置参数就不言而喻了(就是按参数位置下标进行实参–形参一一对应)

void main(){
getPersonInfo("Lili"); // This girl's name is Lili, she is null years old and she lives in null
getPersonInfo("Lili",18,"Chengdu, Sichuan, China"); // This girl's name is Lili, she is 18 years old and she lives in Chengdu, Sichuan, China
}
getPersonInfo ( String name, [int age ,String addr]) => print("This girl's name is $name, she is $age years old and she lives in $addr ");

还有一个可选参数必选放到必选参数后面(这个同ES6 的不定参数规则完全相同呵)

6.3 默认参数值 (使用 ‘=’ 指定)

void main(){
getPersonInfo("Lili"); // This girl's name is Lili, she is 18 years old and she lives in Chengdu, Sichuan, China
}
getPersonInfo ( String name, [int age = 18 ,String addr = "Chengdu, Sichuan, China"]) => print("This girl's name is $name, she is $age years old and she lives in $addr ");

6.4 方法对象

1)方法可以作为对象赋值给其他变量

2)方法可以作为我参数传递给其他方法

void main(){
Function func = printPersonalInfo;
func(); // Hello world! var studentList = ["Binbin","Tingting","Mingmint"]; // 将getEachFromList方法作为参数传递个forEach;进行元素打印
studentList.forEach(getEachFromList); // Binbin
// Tingting
// Mingmint print(powerOperator(studentList,powerFn)); // [BinbinBinbinBinbin, TingtingTingtingTingting, MingmintMingmintMingmint]
}
printPersonalInfo() => print("Hello world!");
getEachFromList(val) => print(val); powerOperator(List<String> list,String powerFn(str)){
for(var i =0;i< list.length; i++){
list[i] = powerFn(list[i]);
}
return list;
} String powerFn(str) => str*3;

6.5 匿名方法 (anonymous)

void main(){
var fn = (){
print("hello dart !");
};
fn (); // hello dart ! // 定义一个自动运行方法,同js (function($){}(window.document))()
((){
print("I am an automated methed!"); // I am an automated methed!
})();
var studentList = ["Binbin","Tingting","Mingmint"];
print(powerOperator(studentList,(str) => str * 3)); // [BinbinBinbinBinbin, TingtingTingtingTingting, MingmintMingmintMingmint]
}
printPersonalInfo() => print("Hello world!");
getEachFromList(val) => print(val); powerOperator(List<String> list,String powerFn(str)){
for(var i =0;i< list.length; i++){
list[i] = powerFn(list[i]);
}
return list;
}

6.6 闭包

这个一直都是个难啃的骨头在js python 中都有它的身影,理解起来都是那么的不容易

理论:

1)闭包是一个方法(对象)

2)闭包定义在其它方法内部

3)闭包能够访问外部方法内的局部变量,并持有其状态

看这个最简单的例子:

void main(){
var fnc = outsideFn();
fnc(); // 0
fnc(); // 1
fnc(); // 2
fnc(); // 3
fnc(); // 4
fnc(); // 5
} outsideFn(){
int count = 0;
return (){
print(count++);
};
}

七、 面向对象(万物皆对象哈哈这是编程界的最高信仰)

7.1 类、对象

先背一下对象和类的概念

对象:用来描述客观事物的一个实体,由一组属性和方法构成

对象的静态特征称为对象的属性(用来描述对象静态的特征的一个数据项)

对象的动态特征称为对象的方法(对象的行为)

类:定义了对象将会拥有的特征(属性)和行为(方法)

类属性:对象所拥有的静态特征在类中表示时称为类的属性(在类中定义对象的静态特征时)

类的方法:对象执行的操作称为类的方法

1) 使用 class 声明一个类(同 es6、java)

2) 使用关键字 new 创建对象(同 es6、java),new 可以省略

3) 所有对象都继承于Object类

属性与方法

1)属性默认会生成getter 和setter 方法

2)使用final申明的属性只有getter方法

3)属性和方法通过 . 访问

4)方法不能被重载 (这个和java不同)

void main(){
var person = Person();
person.name = "Wangxiaohu";
person.age = 13;
person.work(); // Wangxiaohu is a programmer, 13 years old this year, because he like to code very much ,so he is typing code!
} class Person{
// 声明该类的属性(也称为实例变量)
String name;
int age; void work(){
print("$name is a programmer, $age years old this year, because he like to code very much ,so he is typing code!");
}
//error: The name 'work' is already defined. (方法不能重置,因为已经定义)
// void work(int score){}
}

5)类及成员可见性

这个就没有了java 中的(public、private、protected、default)这四个修饰符了;

Dart 中的可见性以library(库)为单位

默认情况下,每一个Dart 文件就是一个库

使用 _ 表示库私有性(有点类似js 私有函数定义)

使用import 导入库

我们把上面那个案例稍微改一哈

main.dart

import 'Person.dart';

void main(){
var person = Person();
person.name = "Wangxiaohu";
person.age = 13;
person.work(); // Wangxiaohu is a programmer, 13 years old this year, because he like to code very much ,so he is typing code!
}

Person.dart

class Person{
// 声明该类的属性(也称为实例变量)
String name;
int age; void work(){
print("$name is a programmer, $age years old this year, because he like to code very much ,so he is typing code!");
}
//error: The name 'work' is already defined. (方法不能重置,因为已经定义)
// void work(int score){}
}

注意:Person.dart 中class Person 如果改为 class _Person 就变成了了私有了只有在当前的Person.dart文件中可以使用;对外不可见

7.2 计算属性

计算属性vue 中的(computed)呵呵!好像不是耶!

1)计算属性的值是通过计算而来的(废话),本身不存储值

2) 计算属性赋值,是通过计算转换到其他实例变量(这个有点抽象)

void main(){
var rect = new Rectangle();
rect.height= 20;
rect.width = 10;
print(rect.area); // 200 rect.area = 200;
print(rect.width); // 10.0
} class Rectangle{
num width,height;
num get area => width * height;
set area(val) => width = val /20;
}

7.3 构造方法

1) 一个类没有显示指定 构造方法,则使用默认构造

2)如果显示指定了构造方法,默认构造方法将失效

3)构造方法不能被重载

void main(){
var person = new Person(); // 看这里就提示 error: 2 required argument(s) expected, but 0 found. 希望2个参数,但实际1个都没得
person.age = 18;
person.name = "Perpar";
}
class Person{
String name;
int age;
// 未显示指定构造,将使用默认构造如:
// Person(){
//
// } // 如果显示指定构造,默认构造将无效 如:
Person(String name,int age){ // 也可以使用 dart语法糖 简写为 Person(this.name, this.age)
this.name = name;
this.age = age;
}
}

使用 dart 构造方法语法糖为final 属性赋值

void main(){
var person = new Person("jack");
print(person.name); // jack
}
class Person {
final String name; // this.name会在构造方法执行之前进行参数赋值
Person(this.name);
}

命名构造方法

1) 使用 类名.方法 的形式来实现一个类多个构造方法

void main(){
var person = new Person("jack",18);
var person2 = new Person.withName("Pingping");
var person3 = new Person.withAge(19); print(person.name); // jack
print(person2.name); // Pingping
print(person3.age); // 19
}
class Person {
final String name;
int age;
// this.name会在构造方法执行之前进行参数赋值
Person(this.name,this.age);
Person.withName(this.name);
Person.withAge(this.age);
}

7.4 常量构造方法

1)如果类是不可变状态,就可以吧对象定义为编译时常量

2) 使用 const 声明构造方法,并且所有变量都为final

3)使用const 声明对象(可以省略)

使用场景:如果在开发过程中,我们想限制某个类实例化以后 它的 所有属性 只能被赋值一次,那设置const 就ok了

void main(){
const person = const Person("Lili", 18);
person.study(); // I am reading the JAVA programming ideas here!
}
class Person {
final String name;
final int age;
// 属性会在构造方法执行之前进行参数赋值
const Person(this.name,this.age);
study(){
print("I am reading the JAVA programming ideas here!");
}
}

7.5 工厂构造方法

1) 工厂构造方法类似与设计模式的工厂模式

2) 在构造方法前使用factory 关键字来创建一个工厂构造方法

3) 在工厂构造方法中可以返回一个对象


void main() {
var factoryConstruct = Logger("firstLog");
factoryConstruct.printLog("Hi, hello I am coming to the factory !");
}
class Logger{
final String name;
static final Map<String,Logger> _cache = <String,Logger>{}; /**
* 使用工厂构造方法 根据 传入的 name 到_cache map中查找如果存在就返回;
* 如果不存在就调用_internal对name进行赋值,同时将该构造缓存与_cache中,
* 同时将其返回给调用者
*/
factory Logger(String name){
if(_cache.containsKey(name)){
return _cache[name];
}else{
final logger = Logger._internal(name);
_cache[name] = logger;
return logger;
}
}
Logger._internal(this.name); // 一个私有的内部构造方法 printLog(String msg) => print(msg); // Hi, hello I am coming to the factory !
}

7.6 初始化列表

1)初始化列表会在构造方法执行之前执行

2)使用逗号分隔初始化表达式

3)常用于对final 变量赋值

void main(){
var map = {"name":"Lili","age":18,"addr":" Chengdu, Sichuan, China"};
var person = new Person(map);
person.sayInfo(); // Hello, Everybody; my name is Lili, I am 18 years old this year, I come from Chengdu, Sichuan, China
}
class Person{
final String name;
final String addr;
int age; // 使用 初始化列表为final 属性赋值
Person(Map map):name = map["name"],addr = map["addr"]{
age = map["age"];
} sayInfo(){
print("Hello, Everybody; my name is $name, I am $age years old this year, I come from $addr");
}
}

7.7 静态成员

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

2)静态成员不能访问非静态成员,非静态成员可以访问静态成员(复习java了哈哈)

3)类中的常量需要使用static const 进行声明

void main(){
var person = new Person();
Person.work(); // I earned a thousand yuan for my work,so I saved 100 yuan,Now the total deposit is ¥20100.0 。
person.shop(); // I went to the store and bought a dress and used 100 yuan,so now the total deposit is ¥19100.0
} class Person{ // 类里面声明常量需要使用 static const
// const String hobby="jog"; // error: Only static fields can be declared as const.
static const String hobby = "jog"; double salaries = 1000.00;
static double deposit = 20000.00; static work(){
// salaries += 120.00; // 静态成员不能访问非静态成员(double salaries为非静态属性,是实例对象的一个属性)error: Instance members can't be accessed from a static method.
deposit += 100.00;
print("I earned a thousand yuan for my work,so I saved 100 yuan,Now the total deposit is ¥$deposit 。");
} shop(){
deposit -=1000.00; // 非静态成员可以访问静态成员
print("I went to the store and bought a dress and used 100 yuan,so now the total deposit is ¥$deposit");
}
}

7.8 对象操作符

1) 条件成员访问 : ?.

void main(){
Person person;
person?.work(); // 如果实例为空就不向后执行【该操作符可以避免对象空指针的问题】
person?.name; // 同上 // person.name; // Unhandled exception: NoSuchMethodError: The getter 'name' was called on null. Receiver: null Person person2 = Person();
person2.work(); // I am working in the company
}
class Person{ String name;
int age;
work(){
print("I am working in the company");
}
}

2)类型转换 :as

3)是否指定的类型:isis!

void main(){

 var person ;
person = "";
// person.work(); //该person是个字符串类型没有实例方法work Unhandled exception: NoSuchMethodError: Class 'String' has no instance method 'work'.
// (person as Person).work(); // string 类型不能转为Person Unhandled exception:type 'String' is not a subtype of type 'Person' in type cast
person = Person();
// 是is 关键字进行类型判断 (如同java 的 instanceOf); 反之使用 is! 关键字判断不是 该类型
if(person is Person){
person.work(); // I am working in the company
}
}
class Person{ String name;
int age;
work(){
print("I am working in the company");
}
}

4)级联操作 : ..

void main(){
// 和 build 设计模式 很类似
var person = new Person();
person .. name = "Lili"
..age = 18
..work(); // I am Lili,I am 18 years old.
// 也可以使用这种匿名对象的方式
new Person()..name = "Tingting"
..age = 19
..work(); // I am Tingting,I am 19 years old.
}
class Person{ String name;
int age;
work(){
print("I am $name,I am $age years old.");
}
}

7.9 对象的call 方法

dart 中 方法可以作为对象来使用,对象也可以作为方法来使用

1)如果类实现了call() 方法,则该类的对象可以作为方法使用

void main(){
var person = new Person();
print(person("Tingting",18)); // I am Tingting,I am 18 years old.
}
class Person{ String name;
int age;
// 该对象实现了call 后,他的实例就可以当成方法来使用了
String call(String name,int age){
return "I am $name,I am $age years old.";
}
}

八、 面向对象高级扩展

面向对象三大特性(和java一样):封装、继承、多态

1)继承,继承中的构造方法(extends)

2)抽象类(abstract)

3)接口(interface)

4)Mixins(这个同vue的mixin类似),操作符的覆写

8.1 继承(extends)

1)使用extends 关键字继承一个类

2)子类会继承父类可见的属性和方法,不会继承构造方法

3)子类能够覆写父类的方法,getter和setter

4)和java一样一个子类只能继承一个父类,同样使用继承能实现多态的特性

Student.dart

import 'Person.dart';

void main(){
var student = new Student();
student.name ="Lili";
student.age = 13;
print(student.isAdult); // false
student.sayInfo(); // I nam is Lili,I am 13 years old,so I am underage
// student._birthday = "199-0909"; // 这里是不可以调用父类的_birthday 属性的,因为他是私有,对外不可见
} class Student extends Person{
study(){
print("I am a student .");
}
}

Person.dart

class Person{

  String name;
int age;
String _birthday; bool get isAdult => age > 18; void sayInfo(){
print("I nam is $name,I am $age years old,so ${isAdult ? 'I am an adult':'I am underage'} ");
} }

但我们觉得不爽了想在 13岁就让自己成年,怎么搞? 直接就重写父类的isAdult

import 'Person.dart';

void main(){
var student = new Student();
student.name ="Lili";
student.age = 13;
print(student.isAdult); // true
student.sayInfo(); // I nam is Lili,I am 13 years old,so I am an adult
} class Student extends Person{
study(){
print("I am a student .");
} @override
// TODO: implement isAdult
bool get isAdult => age > 12;
}

5)多态(将子类实例赋值给父类)

使用场景:如果一个父类有多个子类实现时就可以使用多态

import 'Person.dart';

void main(){
Person person = new Student();
// person.study(); // 只是将student类的实例给了person ,但是person还是原本的Person所以它里面并没有study方法 error: The method 'study' isn't defined for the class 'Person'.
person.name = "Tingting";
person.age = 22;
person.sayInfo(); // I nam is Tingting,I am 22 years old,so I am underage
} class Student extends Person{
study(){
print("I am a student .");
} @override
// TODO: implement isAdult
bool get isAdult => age > 24;
}

8.2 继承中的构造方法

1)子类的构造方法默认会调用父类的无名无参的构造方法

void main(){
Person person = new Student(); // I am Person class.
}
class Person{
String name;
Person(){
print("I am Person class.");
}
} class Student extends Person{ }

2)如果父类没有无名无参的构造方法,则需要显示调用父类的构造方法

3)在构造方法参数后面使用: 显示调用父类构造方法


void main(){
Person person = new Student("Lili");
print(person.name); // Lili
}
class Person{
String name;
Person(this.name);
Person.withOther(this.name);
} class Student extends Person{
Student(String name): super(name); // 或者super.withOther(name) }

构造方法执行顺序

1) 父类的构造方法在子类构造方法体开始执行的位置调用

2)如果有初始化列表,初始化列表会在父类构造方法之前执行


void main(){
Person person = new Student("Lili","sichuan");
// 是关键字is 判断类型调用studentSay
if(person is Student){
person.studentSay(); // I am Lili,I come from sichuan.
}
}
class Person{
String name;
Person(this.name);
Person.withOther(this.name);
} class Student extends Person{
final String addr;
// 初始化列表要放置在调用父类构造方法之前然后使用 逗号隔开,否则报错,
Student(String name,String address): addr = address, super(name); // 或者super.withOther(name) studentSay(){
print("I am $name,I come from $addr.");
}
}

8.3 抽象类

1)使用abstract定义,不能直接被实例化


void main(){
Person person = new Person();// error: Abstract classes can't be created with a 'new' expression. }
abstract class Person{ }

2)抽象方法不用 abstract修饰,无实现(就是没有方法体的方法)

abstract class Person{
void work(); // 抽象方法
}

3) 抽象类可以没有抽象方法

4)有抽象方法的类必须是抽象类

class Person{
void work(); //非抽象类,定义抽象方法会报错 error: 'work' must have a method body because 'Person' isn't abstract.
}

void main(){
Person person = new Student();
person.work(); // I am a student so I don't have to work }
abstract class Person{
void work();
} class Student extends Person{
@override
void work(){
print("I am a student so I don't have to work");
}
}

8.4 接口

1) 类和接口是统一的,类就是接口

2)每个类都隐式的定义了一个包含首页实例成员的接口

3)如果是复用已有类的实现,则使用继承(extends

4)如果只是使用已有类的外在行为,使用接口(implements

class Person{
String name;
int get age => 18;
void work(){ }
} class Student implements Person{
@override
String name; // TODO: implement age
@override
int get age => 22; @override
void work() {
// TODO: implement work
} }

从上面案例可知 dart 中 class 申明的类其实也可以当成接口来实现

【dart】中所以类(包括抽象类)都可以当做接口来实现,

平时开发中建议使用抽象类来作为接口使用,这个更像是一个接口

如果使用一个普通类来作为一个接口,会让人感觉怪怪的

abstract class Person{
void work();
void study();
void earnMoney();
} class Student implements Person{
@override
void earnMoney() {
// TODO: implement earnMoney
} @override
void study() {
// TODO: implement study
} @override
void work() {
// TODO: implement work
} }

8.5 Mixins

使用mixins 首先得使用extends 后再使用 with 类1,类2,…

1)Mixins 类似于多继承,是在多类多继承中重用一个类代码的方式

void main(){
Superman superman = new Superman();
superman.sayMe(); // I am a superman,haha...
// 这里值得注意的是当这个几个类中都有相同的方法时,调用将会按照with 后的类顺序来寻找,找到最后一个类如果有就执行其中的方法;
superman.run(); // Computer run... } class Aircraft{
void fly(){
print("Aircraft fly...");
}
void run(){
print("Aircraft run...");
}
}
class Car{
void run(){
print("Car run...");
}
} class Computer{
void computed(){
print("Computer computed...");
}
void run(){
print("Computer run...");
}
}
// 如:一个超人拥有飞机的飞行能力、汽车的奔跑能力、电脑的运算能力
class Superman extends Aircraft with Car,Computer{
void sayMe(){
print("I am a superman,haha...");
}
}

2)作为Mixin 的类不能有显示声明构造方法

class Aircraft{

}
class Car{ } class Computer{
Computer(){ // 显示声明 构造方法后 下面继承就会提示错误 }
}
// error: The class 'Computer' can't be used as a mixin because it declares a constructor.
class Superman extends Aircraft with Car,Computer{ }

3)作为Mixin的类只能继承之Object

4) 使用关键字with连接一个或多个mixin


void main(){
Car car = new Car();
car.run(); // Tyre is here.
car.work(); // Work with oil...
Bus bus = new Bus();
bus.run(); // Tyre is here.
bus.work(); // Work with Electric... }
/**
* 引擎抽象类
*/
abstract class Engine{
void work();
}
// 这里都是使用的 implement 而没有使用 extends 继承,是因为使用extends后就没法使用mixin
/**
*石油引擎
*/
class OilEngine implements Engine{
@override
void work() {
// TODO: implement work
print("Work with oil...");
}
}
/**
* 电动引擎
*/
class ElectricEngine implements Engine{
@override
void work() {
// TODO: implement work
print("Work with Electric...");
}
}
/**
* 轮胎类
*/
class Tyre{
String name;
void run(){
print("Tyre is here.");
}
} /**
* 使用mixin组装一个烧油的汽车
* 这里注意如果一个类没有自己的属性和方法是由其他类组合而来,就可以使用这种简写的模式
* 他的完整写法是
* class Car extends Type with OilEngine{
String siteNum;
}
*/
class Car = Tyre with OilEngine;
// 使用mixin组装一个烧电的公交车
class Bus = Tyre with ElectricEngine;

8.6 操作符覆写

1)覆写操作符需要在类中定义

返回类型   operator 操作符 (参数1,参数2,...){
实现体...
return 返回值;
}

2) 如果覆写 == , 还需要覆写对象的hasCode getter 方法

void main (){
Person person1 = new Person("Lili", 18);
Person person2 = new Person("BingBin", 19);
print(person1 > person2); // false
print(person2["age"]); // 19
} class Person{
String name;
int age;
Person(this.name,this.age);
// 重写 > 操作符
bool operator >(Person person){
return this.age > person.age;
} // 重写 []操作符
int operator [](String str){
if(str =="age"){
return this.age;
}
return 0;
}
}

这里还有个生成 覆写== 快捷键





九 、 枚举和类型

9.1 枚举

1)枚举是一种有穷序列集的数据类型

2) 使用enum关键字定义一个枚举

3)常用于代替常量,控制语句等

void main (){
var currentSeason = Season.spring;
switch(currentSeason){
case Season.spring:
print("1-3月");
break;
case Season.summer:
print("4-6月");
break;
case Season.autumn:
print("7-9月");
break;
case Season.winter:
print("10-12月");
break;
default:
print("你输入了什么!");
}
} enum Season{
spring,
summer,
autumn,
winter,
}

枚举特性

1)index 从0开始依次累加

 var currentSeason = Season.spring;
// 获取枚举位置
print(currentSeason.index); // 0

2)不能指定初始值

enum Season{
spring = 10; // 不能定义默认值 error: Expected a method, getter, setter or operator declaration.
summer,
autumn,
winter,
}

3)不能添加方

enum Season{
spring ,
summer,
autumn,
winter,
void work(){} // error: Expected a method, getter, setter or operator declaration.
}

9.2 泛型

1)dart 中类型是可选的,可也是用泛型限定类型

2)使用泛型能有效减少代码重复

void main (){
var list = new List<String>();
list.add("1");
}

泛型的使用

1) 类的泛型

void main (){
var utils = new Utils<int>();
utils.put(100);
var utils2 = new Utils<String>();
utils2.put("100");
} class Utils<T>{
T element;
void put(T element){
this.element = element;
}
}

2) 方法的泛型

void main (){
var utils = new Utils();
utils.put<String>("100"); // 100
} class Utils{ void put<T>(T element){ // 这里和java的泛型方法不一样;java中是将<T>放在方法前面的 如 :void <T> put(T element)
print(element);
}
}

到此 dart 学完了,这个dart 有点类似java 与 JavaScript 的合体,学来还是蛮简单的;接下来抽点时间开始撸flutter app去了。

flutter 填坑之旅(dart学习笔记篇)的更多相关文章

  1. React Native填坑之旅--布局篇

    代码在这里: https://github.com/future-challenger/petshop/tree/master/client/petshop/src/controller 回头看看RN ...

  2. 使用vue开发微信公众号下SPA站点的填坑之旅

    原文发表于本人博客,点击进入使用vue开发微信公众号下SPA站点的填坑之旅 本文为我创业过程中,开发项目的填坑之旅.作为一个技术宅男,我的项目是做一个微信公众号,前后端全部自己搞定,不浪费国家一分钱^ ...

  3. bootstrap-table填坑之旅<一>认识bootstrap-table

    应公司需求,改版公司ERP的数据显示样式.由于前期开发的样式是bootstrap,所以选bootstrap-table理所当然(也是因为看了bootstrap-table官网的example功能强大, ...

  4. React Native填坑之旅--与Native通信之iOS篇

    终于开始新一篇的填坑之旅了.RN厉害的一个地方就是RN可以和Native组件通信.这个Native组件包括native的库和自定义视图,我们今天主要设计的内容是native库方面的只是.自定义视图的使 ...

  5. React Native填坑之旅--Flow篇(番外)

    flow不是React Native必会的技能,但是作为正式的产品开发优势很有必要掌握的技能之一.所以,算是RN填坑之旅系列的番外篇. Flow是一个静态的检查类型检查工具,设计之初的目的就是为了可以 ...

  6. https填坑之旅

    Boss说,我们买了个权威证书,不如做全站式的https吧,让用户打开主页就能看到受信任的绿标.于是我们就开始了填坑之旅. [只上主域好不好?] 不好...console会报出一大堆warning因为 ...

  7. stm32填坑之旅 - stm32f103c8t6点亮板载贴片蓝色LED

    转载请注明:https://www.cnblogs.com/rockyf/p/11691622.html 开篇 开篇一定要精彩,不然路人不理睬!下述是笔者作为arm小白的填坑之旅 没错,这个之前一直从 ...

  8. Dart学习笔记-运算符-条件表达式-类型转换

    Dart学习笔记-运算符-条件表达式-类型转换 一.运算符 1.算术运算符 + (加)- (减)* (乘)/ (除)~/ (取整) %(取余) 2.关系运算符 == (等等) != (不等) > ...

  9. React Native填坑之旅--重新认识RN

    如同黑夜里的一道光一样,就这么知道了F8. F8是每年一次Facebook每年一次的开发者大会.每次大会都会release相应的APP,iOS.Android都有.之前都是用Native开发的,但是2 ...

  10. React Native填坑之旅--Stateless组件

    Stateless component也叫无状态组件.有三种方法可以创建无状态组件. 坑 一般一个组件是怎么定义的: 很久以前的方法: const Heading = createClass({ re ...

随机推荐

  1. 使用python自动监控程序运行过程数据

    操作系统 :CentOS 7.6.1810_x64 Python 版本 : 2.7.5 一.背景描述 工作中会遇到需要监控程序运行过程数据的情况,比如定时执行监控的cmd并记录执行结果,本文提供一种实 ...

  2. 前端开发工具 VS Code 安裝及使用

    一.下载地址 https://code.visualstudio.com/ 下载完后,傻瓜式安装即可 关注公众号"Java程序员进阶"回复"vs"也可获取 二. ...

  3. ACM-NEFUOJ-最小树-Prim算法

    最小树1 Description 某省长调查交通情况,发现本省交通事故发生不断,于是决定在本省内全部修建地铁. 该省长得到的统计表中列出了任意两市之间的距离,为了确保任何两个市都可以直接 或者间接实现 ...

  4. [Java JDK]ResultSet.next()

    1 JDK [jdk1.5doc] Moves the cursor down one row from its current position. A ResultSet cursor is ini ...

  5. [Linux]ln:软链接与硬链接

    1 硬链接与软链接的[语法] 软链接:ln -s 源文件 目标文件 硬链接:ln 源文件 目标文件 [-s : symbolic,符号/代号] 2 软链接/硬链接的[比喻] / (编辑)同步性 [ro ...

  6. day39:MySQL:查询操作之单表查询&多表查询&子查询

    目录 part1:单表查询 1.where条件的使用 2.group 子句 分组分类 3.having 数据在分类分组之后,进行二次数据过滤 4.order by 排序, 按照什么字段进行排序 5.l ...

  7. Java GC基础知识

    对象存活判断 引用计数 在对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加一:当引用失效时,计数器值就减一:任何时刻计数器为零的对象就是不可 能再被使用的 引用计数法的缺陷: publi ...

  8. Visual Studio Code 常见的配置、常用好用插件以及【vsCode 开发相应项目推荐安装的插件】

    一.VsCode 常见的配置 1.取消更新 把插件的更新也一起取消了 2.设置编码为utf-8:默认就是了,不用设置了 3.设置常用的开发字体:Consolas, 默认就是了,不用设置了 字体对开发也 ...

  9. HTML+CSS+JavaScript作业篇

    一.作业题大全 1.1.HTML5表单验证 代码: <!DOCTYPE html> <html lang="en"> <head> <me ...

  10. TIM-PWM输出,占空比改变时机对输出波形的影响

    一.实验概述 以下说明描述三种改变PWM占空比的方式,对于当前PWM输出波形的影响 1.禁止预装载功能,在PWM某一周期波形输出过程中改变占空比值(ccp) 2.禁止预装载功能,在PWM某周期波形输出 ...