本文首发于微信公众号「Android开发之旅」,欢迎关注 ,获取更多技术干货python
Dart从2.0开始变为强类型语言,静态类型。这点和Java、C#等比较类似。也就是说在编译时就已经知道变量的类型那么就是静态类型语言。开发人员在开发的时候须要指定变量的类型。这有什么优势呢? 就是全部类型检查均可以经过编译器来完成。能够提早预报一些琐碎的错误。 同时Dart仍是面向对象的编程语言。像python、Java、Koltin、PHP等等都是面向对象的语言。编程
dart的特性: JIT:即时编译,开发期间作到更快的编译和更快的代码重载。 但也有劣势就是在运行时须要将代码编译为机械码,那么直观感觉就是慢,因此咱们在开发期间有时候会发现卡顿,可是打release包以后效果会变好的缘由。 AOT:事前编译,release期间已经编译为二进制代码,因此加载会更快更流畅。json
任何语言的基础都是数据类型,dart也同样。dart中主要有数字、字符串、布尔、集合和var类型。缓存
num是dart中的数字类型的父类,它有两个子类:int和double。当类型指定为num的时候能够赋值为小数也能够赋值为整数,可是一旦指定了某一个具体的类型,就只能赋值这一类型的值。bash
void _numType() {
num num1 = -2.0; //定义为小数
num num2 = 4; //定义num为你太
int num3 = 5; //只能是整数
double num4 = 6.0; //只能是双精度
}
复制代码
其中这些类型之间是能够相互转换的,如:微信
print(num1.abs()); // 取绝对值 输出 2.0
print(num2.toDouble()); // 转为小数 输出4.0
print(num3.toString()); // 转为字符串 输出"5"
print(num4.toInt()); // 转为整数 输出 6
复制代码
String的定义也比较简单,它可使用单引号也可使用双引号定义,定义一个String类型后面能够经过逗号隔开定义多个变量。在dart中拼接字符串能够是 + 号连接,还可使用 xx,若是是表达式则使用${xxx}将其包裹起来。网络
void _stringType() {
String str1 = 'str1', str2 = "str2"; //定义字符串str1和str2
String str3 = "字符串数据类型"; //定义字符串str3
String str4 = 'str1=$str1;str2=$str2'; //经过$符拼接字符串
String str5 = "str1=" + str1 + " str3=" + str3; //经过+号拼接字符串
}
复制代码
字符串还有一些经常使用的API,好比字符串截取,获取指定字符串位置,匹配字符串开头等等。闭包
print(str3.substring(1, 5)); //符串数据 输出 符串数据
print(str3.indexOf("数据")); // 获取位置 输出 3
print(str3.startsWith("字")); //匹配起始字符串 true
print(str3.replaceAll("字符串", "dart的String")); //替换 输出dart的String数据类型
print(str3.split("数")); //切够字符串 输出[字符串,据类型]
复制代码
dart中布尔类型是强bool类型,只有bool类型的值为true,才被认为是true。bool还有一些经常使用的运算符好比 ||(或) 或者 &&(且) ,在运算的时候,教你们一个口诀就是,且同真为真,或同假为假。编程语言
void _boolType() {
bool success = true; //定义bool值为true
bool failure = false; //定义bool值为false
print(success || failure); //或运算 输出 true
print(success && failure); //且运算 输出 false
}
复制代码
dart中定义集合直接使用List list=[],若是没有指定泛型,默认类型为dynamic类型,集合中能够添加任何数据类型的数据,一旦指定了泛型,那么就只能添加约束的类型数据。除了初始化的时候添加元素另外还能够经过API的方式像集合中添加数据,add添加单一数据,addAll添加集合。还有另一种方式是经过List.generate来生成集合,它的第一个参数表示集合的大小,第二个参数表示集合的元素。ide
void _listType() {
List list = [1, 2, 3, "list"]; //泛型为dynamic
//报 type 'List<dynamic>' is not a subtype of type 'List<int>' 异常
//由于指定了intList的泛型为int 可是list的泛型为dynamic,随意赋值失败
//List<int> intList = list;
List<int> intList2 = [1, 2, 3, 4, 5]; //定义int集合
list.add("hello"); //添加单一元素
list.addAll(intList2); //添加集合
print(list); //输出 [1, 2, 3, "list","hello",1, 2, 3, 4, 5]
List<String> strList = List.generate(2, (index)=> "我是第$index个元素"); //经过generate定义一个String集合
print(strList); //输出 [我是第0个元素, 我是第1个元素]
}
复制代码
有了集合那么咱们就须要遍历它,dart中经常使用的遍历集合方式有:
for (int i = 0; i < list.length; i++) {
print(list[i]);
}
for (var data in list) {
print(data);
}
list.forEach((it) {
print(it);
});
复制代码
上面三种遍历方式输出结果都为:
1, 2, 3, "list","hello",1, 2, 3, 4, 5
复制代码
Map类型是将key和value相关联的对象,key和value能够是任意类型的数据,而且key是惟一的,若是key重复那么后添加的会覆盖以前添加的数据。定义map类型直接看代码:
void _mapList() {
Map map = {"lisi": 20, "zhangsan": 24}; //直接经过 {key:value} 方式定义
Map map2 = {};
map2[11] = 20;
map2["zhangsan"] = "24";
//上面两个效果是同样的且都没有指定泛型。
Map<int, int> intMap = {1: 2, 3: 4}; //指定map的泛型
}
复制代码
下面咱们看下Map的遍历:
map.forEach((key, value) {
print(
"key:$key,value:$value"); //输出 key:lisi,value:20 和 key:zhangsan,value:24
});
map.map((key, value) {
return MapEntry(value, key); //返回一个新的map对象,咱们将key value值进行颠倒后返回
}).forEach((key, value) {
print("key:$key,value:$value"); //输出 key:20,value:lisi 和 key:24,value:zhangsan
});
for(var key in map.keys){ //遍历map的key元素 同理还能够遍历map.values
print(key); //输出 lisi 和 zhangsan
}
复制代码
dynamic:动态数据类型,是全部Dart对象的基础类型, 在大多数状况下,一般不直接使用它,经过它定义的变量会关闭类型检查,这意味着 dynamic x = 'hello world'; 调用x.foo()方法时静态类型检查不会报错,可是运行时会crash,由于x并无foo()方法,因此建议你们在编程时不要直接使用dynamic。
var:是一个关键字,意思是“我不关心这里的类型是什么。”,系统会自动推断类型runtimeType;并且一旦指定了类型,就不能够修改。
Object:是Dart对象的基类,当你定义:Object obj=xxx 时这时候系统会认为obj是个对象,你能够调用obj的toString()和hashCode()方法,由于Object提供了这些方法,可是若是你尝试调用obj.foo()时,静态类型检查会进行报错。
综上不难看出dynamic与Object的最大的区别是在静态类型检查上。
定义一个dart类,使用class关键字加上类名,构造方法和类名相同,默认全部的类都是继承Object的。其中能够定义一些方法和变量,如:
class Person {
String name;
int age;
//标准构造方法
Person(this.name, this.age);
//重载父类的toString方法 也是多态的重要体现
@override
String toString() {
return "name=$name,age=$age";
}
}
复制代码
一个类继承另外一个类使用关键字extends,若是父类没有默认无参构造函数,那么子类须要使用super对父类进行初始化,子类的变量使用this.xxx来指定初始化,如:
class Worker extends Person {
String workType;
String workAddress;
//经过this来初始化子类字段,将其余字段交由父类初始化
Worker(this.workType,this.workAddress,String name, int age) : super(name, age);
}
复制代码
上面代码中的 :super(name,age) 被称做为初始化列表,除了调用父类构造器,还能够初始化实例变量,不一样的初始化变量之间用逗号隔开。
class Worker extends Person {
String workType;
String workAddress;
String companyName;
//经过this来初始化子类字段,将其余字段交由父类初始化,这里指定了companyName的初始化。
//若是要初始化变量,那么其不能够在构造方法中定义
Worker(this.workType, this.workAddress, String name, int age)
: companyName = "world",
super(name, age);
}
复制代码
咱们还能够经过命名构造函数的方式初始化实例类。使用就是 类名.xx() 便可,主要注意的是当有变量的类型是final的时候,命名构造方法就要求其在构造方法中指定初始化。
class Worker extends Person {
......
//命名构造函数
Worker.begin(Worker work) : super(work.name, work.age) {
print("命名构造函数");
}
//假若有变量final String workAddress,那么就须要在构造方法中指定:
//Worker.begin(Worker work,this. workAddress) : super(work.name, work.age) {
// print("命名构造函数");
//}
}
复制代码
工厂构造函数就是都只返回同一个实例类,能够理解为Java中的单例模式。
class Logger {
static Logger _logger;
factory Logger() {
if (_logger == null) {
_logger = Logger._initInstance();
}
return _logger;
}
//经过命名构造函数初始化
Logger._initInstance();
}
复制代码
还有一种构造方法是命名构造和工厂构造的结合体,一般在网络请求的时候将json映射为object的时候使用,它有一个好处就是不须要将类的final变量做为参数传递给构造方法。提供了一种灵活获取类对象的方式。定义格式:factory 类名.方法名。
class Worker extends Person {
......
factory Worker.workHard(Worker work) {
return Worker.begin(work, "");
}
}
复制代码
dart默认都会隐式的定义setter方法,对非空的变量还会增长getter方法。可是加了私有后,外界就没法访问变量了,须要咱们手动的添加set和get方法。
class Worker extends Person {
......
double _salary;
set salary(double value) => _salary = value;
get salary => _salary;
......
}
复制代码
使用 abstract 修饰符来定义一个抽象类,该类不能被实例化。抽象类在定义接口的时候很是有用,实际上抽象类中也包含一些实现。若是一个类继承了抽象类要么实现它的抽象方法,要么也将本身定义成抽象类。一个抽象类中不必定要有抽象方法,可是有抽象方法的类必定是抽象类。
//抽象类
abstract class Animal {
//抽象方法
void eat();
}
//实现抽象类
class Dog extends Animal {
//实现eat方法
@override
void eat() {
print("啃骨头");
}
}
复制代码
mixins 是在多个类层次结构中重用代码的一种方式。要使用 mixins ,在 with 关键字后面跟一个或多个 mixin 的名字(用逗号分开),而且with要用在extends关键字以后。
mixins的特征:实现 mixin ,就建立一个继承 Object 类的子类(不能继承其余类),不声明任何构造方法,不调用 super。
//声明mixins类
class Pig {
void action() {
print("吃完就睡");
}
}
//使用mixins类,能够复用它的action方法
class Cat extends Animal with Pig {
@override
void action() {
print("抓老鼠");
}
@override
void eat() {
print("吃猫粮");
}
}
复制代码
方法是由返回值类型+方法名+参数构成。其中返回值类型可缺省,也可为void或者具体的类型。正常状况下都是由方法名的,但有一种特殊就是匿名方法。参数分为参数类型和参数名,其中参数类型可缺省。参数又分为可选参数和默认参数,他们都使用 {} 来定义。
class FunClass {
//city为可选参数,town为默认参数
String fromWhere(country, {String city, String town = "小红帽村"}) {
if (city != null) {
return "我来自 $country $city $town";
} else {
return "我来自 $country $town";
}
}
}
复制代码
咱们来调用打印下看看:
FunClass funClass = FunClass();
print(funClass.fromWhere("格林国")); //输出 我来自 格林国 哈哈村
print(funClass.fromWhere("格林国", city: "童话镇"));//输出 我来自 格林国 童话镇 哈哈村
复制代码
匿名方法有时候也被称为 lambda 或者 closure 闭包,能够把匿名方法赋值给一个变量,直接调用变量名便可。
var printI = (i) => print(i);
复制代码
使用:
FunClass funClass = FunClass();
funClass.printI(999);
复制代码
泛型主要是解决类、接口、方法的复用性、以及对不特定数据类型的支持。
class Cache<T> {
static final Map<String, Object> _cached = Map();
void setItem(String key, T value) {
_cached[key] = value;
}
///泛型方法
T getItem(String key) {
return _cached[key];
}
}
复制代码
这里咱们定义了一个缓存类,存储的类型被定义为泛型,提升代码的复用度。
有时候咱们在实现相似通用接口的泛型中,指望的类型是某些特定类型时,这时可使用类型约束。
class Member<T extends Person> {
T _person;
///泛型做用:约束参数类型
Member(this._person);
String fixedName() {
return 'fixed:${_person.name}';
}
}
复制代码
本文主要是讲解了在Flutter中经常使用到的dart的基础知识,固然还有其余不少的知识点没有涉及到。这里推荐几个dart学习网站给你们使用。
我已经将所有Demo源码上传到后台,关注公众号回复「dart基础」便可得到下载连接。
若是你以为文章还不错,请你们点赞分享下,你的确定是我最大的鼓励和支持。
推荐阅读
Flutter混合开发(一):Android项目集成Flutter模块详细指南