俗话说 ‘工欲善其事必先利其器’ 想要撸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. 在Linux中安装containerd作为kubernetes的容器运行时

    概述 从kubernetes1.24开始的版本移除了内置的docker支持,用户可以自行选择需要使用的容器运行时,比如containerd.CRI-O.Docker Engine等等,这里我们采用二进 ...

  2. 详解uniapp和vue在路由方面的不同和联系

    Uniapp 和 Vue 在路由方面有相似之处,因为 Uniapp 是基于 Vue 的.Uniapp 的路由系统是通过 Vue Router 实现的,因此两者有许多相同的概念和 API. 相同点: 都 ...

  3. Java面试——RPC

    一.RPC 服务的原理 [1]Socket 套接字:网络上的两个程序通过一个双向的通信连接实现数据的交换,这个链接的一端称为 Socket.可以实现不同计算机之间的通信,是网络编程接口的具体实现.So ...

  4. VirtualBox下宿主机和Linux虚拟机共享文件配置方法

    VirtualBox版本-5.2.8 Linux版本-Ubuntu16.04 2020.03.31 一.首先在宿主机上新建一个文件夹,这里命名为共享文件夹(如果读者自行命名记得后文全部替换),存放了一 ...

  5. grub 命令使用

    命令列表 ubuntu 的 iso 盘内一般有 command.lst 这个文件,里面是 grub 支持的命令 加载字体 ( 方便中文显示 ) grub> loadfont $prefix/fo ...

  6. 最新版本 Stable Diffusion 开源AI绘画工具之部署篇

    目录 AI绘画 本地环境要求 下载 Stable Diffusion 运行启动 AI绘画 关于 AI 绘画最近有多火,既然你有缘能看到这篇文章,那么相信也不需要我过多赘述了吧? 随着 AI 绘画技术的 ...

  7. MarkdownStudy01markdown用法

    一级标题 二级标题 三级标题 字体 Hello,Word! Hello,Word! Hello,Word! Hello,Word! 引用 好好学Java 分割线 图片 超链接 点击跳转 列表 A B ...

  8. PyQt5学习 (4)--QAbstractButton(下)

    QAbstractBUtton:   所有按钮控件的基类   提供按钮的通用功能   继承自QWidget   属于抽象类别,不能直接去使用,必须借助于子类(除非你觉得子类不够用,想自定义一个按钮) ...

  9. Python 霸榜的一周,又有什么新 AI 力作呢?「GitHub 热点速览」

    GPT 带火了一波语言模型,LLaMA 和 Alpaca 也在持续发力.依旧是各类 GPT 后缀霸榜 GitHub trending 的一周,为此特推部分专门收录了两个比较不错的 GPT 应用.而作为 ...

  10. 设计模式(三十)----综合应用-自定义Spring框架-自定义Spring IOC-定义bean、注册表相关类

    现要对下面的配置文件进行解析,并自定义Spring框架的IOC对涉及到的对象进行管理. <?xml version="1.0" encoding="UTF-8&qu ...