本片文章有点长,主要讲了 Dart 中 类、泛型和库 几个重要的概念。请耐心看下去。并无给出过多的解释,我以为你们经过实例慢慢去消化,本身去理解,才是对你们最大的帮助。若有不合适,评论留言,下次我会给每一段代码更多的解释算法
类(Class)是面向对象程序设计,实现信息封装的基础。类是一种用户定义的类型。每一个类包含数听说明和一组操做数据或传递消息的函数。类的实例称为对象。json
Dart是一门使用类和单继承的面向对象语言,具备类和基于mixin的继承。全部的对象都是一个类的实例,全部的类都继承自Object。基于mixin的继承意味着尽管任何一个类(除了Object)都只有一个父类,可是类主体能够在多个类层次结构中复用。网络
Dart的类与其它语言都有很大的区别,好比在dart的类中能够有无数个构造函数,能够重写类中的操做符,有默认的构造函数,因为dart没有接口,因此dart的类也是接口,所以你能够将类做为接口来从新实现async
使用new语句来构造一个类,构造函数的名字多是 ClassName
,也能够是 ClassName.otherName
ide
var example = new Example(1, 2); //new 可省略 var example = Example(1, 2);
print(example); // Example(1, 2)
// 这种写法是否是很像 JAVA 啊
class Example {
int x;
int y;
Example(int x, int y) {
this.x = x;
this.y = y;
}
}
// 但在 Dart 中是能够简化成这样的 (推荐)
class Example {
int x;
int y;
Example(this.x, this.y);
}
复制代码
使用命名构造函数能够为一个类实现多个构造函数, 或者使用命名构造函数来更清晰的代表你的意图函数
var example = Example.fromJson({'x': 2, 'y': 2});
class Example {
int x;
int y;
Example(this.x, this.y);
// 命名构造函数
Example.fromJson(Map json) {
x = json['x'];
y = json['y'];
}
}
复制代码
有时候构造函数的目的只是重定向到该类的另外一个构造函数。一个重定向构造函数是没有代码的,在构造函数声明后, 使用冒号调用其余构造函数post
var example = Example.alongXAxis(0);
print(example);
class Example {
int x;
int y;
Example(this.x, this.y);
// 重定向构造函数,使用冒号调用其余构造函数
Example.alongXAxis(int x) : this(x, 0);
}
复制代码
在构造函数体执行以前能够初始化实例参数。 使用逗号分隔初始化表达式。初始化列表很是适合用来设置 final 变量的值测试
class Example {
final String name;
final int age;
final String description;
// 初始化列表
Example(x, y) :
x = x,
y = y,
description = description;
}
复制代码
class Parent {
int x;
int y;
// 父类命名构造函数不会传递
Parent.fromJson(x, y)
: x = x,
y = y {
print('父类命名构造函数');
}
}
class Child extends Parent {
int x;
int y;
// 若超类没有默认构造函数,须要手动调用超类其余构造函数
Child(x, y) : super.fromJson(x, y) {
// 调用父类构造函数的参数没法访问 this
print('子类构造函数');
}
// 在构造函数的初始化列表中使用 super(), 须要把它放到最好
Child.fromJson(x, y)
: x = x,
y = y,
super.fromJson(x, y) {
print('子类命名构造函数');
}
}
复制代码
注意事项:
定义 const 构造函数要确保全部实例变量都是 **final **
const 关键字放在构造函数名称以前
class Example {
// 定义 const 构造函数要确保全部实例变量都是 final
final int x;
final int y;
static final Example origin = const Example(0, 0);
// const 关键字放在构造函数名称以前,且不能有函数体
const Example(this.x ,this.y);
}
复制代码
class Singleton {
String name;
// 工厂构造函数没法访问this,因此这里要用 static (这个变量是属于类的,而不是属于对象的)
static Singleton _cache;
// 工厂方法构造函数,关键字 * factory *
factory Singleton([String name = 'singleton']) => Singleton._cache ??= Singleton._newObject(name);
// 定义一个命名构造函数来生产实例
Singleton._newObject(this.name);
}
=========================================================================================
// 工厂函数
class Massage {
void doMassage(){
print('按摩');
}
}
class FootMassage extends Massage {
@override
doMassage() {
print('脚底按摩');
}
}
class BodyMassage extends Massage {
@override
void doMassage() {
print('全身按摩');
}
}
class SpecialMassage extends Massage {
@override
void doMassage() {
print('特殊按摩');
}
}
Massage massageFactory(String type){
switch (type) {
case 'foot':
return new FootMassage();
case 'body':
return new BodyMassage();
default:
return new SpecialMassage();
}
}
复制代码
get
和 set
关键字定义 getter 和 setterclass Rectangle {
int left;
int top;
int width;
int height;
Rectangle(this.left, this.top, this.width, this.height);
int get right => left + width; // 获取right值
set right(int value) => left = value - width; //设 置right值,同时left也发生变化
int get bottom => top + height;
set bottom(int value) => top = value - height;
}
复制代码
Dart 抽象类主要用于定义标准,子类能够继承抽象类,也能够实现抽象类接口,抽象类经过 abstract
关键字来定义
implement
一个普通类。Dart 任何一个类都是接口implement
多个接口extends抽象类 和 implements的区别:
经典案例:
// 定义一个抽象类,并定义两个抽象方法
abstract class Animal {
eat();
run();
printInfo() {
print('我是一个抽象类里面的普通方法');
}
}
// 定义一个 Dog 继承 Animal 并重写其中的方法
class Dog extends Animal {
@override
eat() {
print('小狗在吃骨头');
}
@override
run() {
print('小狗在跑');
}
}
class Cat extends Animal {
@override
eat() {
print('小猫在吃老鼠');
}
@override
run() {
print('小猫在跑');
}
}
main() {
Dog dog = Dog(); // 实例化 Dog
dog.eat(); // 小狗在吃骨头
dog.run(); // 小狗在跑
dog.printInfo(); // 我是一个抽象类里面的普通方法
Cat cat = Cat();
cat.eat(); // 小猫在吃老鼠
cat.run(); // 小猫在跑
cat.printInfo(); // 我是一个抽象类里面的普通方法
}
复制代码
不知道你们知不知道 @override 是个啥,能够当作是重写吧
实现 call() 方法可让类像函数同样可以被调用
class TransferClass {
call(String a, String b, String c) => '$a $b $c!';
}
main() {
var transfer = TransferClass();
var String = transfer("dart","flutter","top");
print('$test'); // dart flutter top!
print(transfer.runtimeType); // TransferClass
print(test.runtimeType); // String
print(transfer is Function); // false
}
复制代码
使用泛型,不少的容器对象,在建立对象时均可以定义泛型类型,跟 Java 同样
var list = List<String>();
var map = Map<int, String>();
// 运行时可判断泛型
print(list is List<String>); // true
print(list.runtimeType); // JSArray<String>
复制代码
Dart1.21 开始可使用泛型函数
泛型函数能够在如下几个地方使用类型参数:
<1> 函数的返回值类型
<2> 参数的类型
<3> 局部变量的类型
main() {
K addCache<K, V>(K key, V value) {
K temp = key;
print('${key} : ${value}'); // dart : flutter
return temp;
}
var key = addCache('dart', 'flutter');
print(key); // dart
}
复制代码
要在使用构造函数时指定一个或多个类型,可将类型放在类名称后面的尖括号<...>中
main() {
var phone = Phone<String>('6888');
print(phone.mobileNumber); // 6888
}
class Phone<T> {
final T mobileNumber;
Phone(this.mobileNumber);
}
复制代码
实现泛型类型时,您可能但愿限制其参数的类型,能够在<>里面使用extends
main() {
var footMessage = FootMessage();
var message = Message<FootMessage>(footMessage);
message.message.doMessage(); // 脚底按摩
}
class Message<T extends FootMessage> {
final T message;
Message(this.message);
}
class FootMessage {
void doMessage() {
print('脚底按摩');
}
}
复制代码
使用 import
去指定如何在另外一个库的范围内使用来自一个库的命名空间
import 后的参数必须参数为库的 URL (Uniform Resource Identifier统一资源标识符)
例如,Dart web应用程序一般使用 Dart : html 库,它们能够像这样导入:
import 'dart:html';
复制代码
对于内置的库,URI 使用特殊的 dart: scheme
import 'dart:math';
import 'dart:io';
import 'dart:convert';
....
void main() {
print(sqrt(4)); // math > 开平方2.0
}
复制代码
对于其余的库,你可使用文件系统路径或者 package: scheme
若是须要载入第三方库咱们是须要在 pubspec.yaml 文件中声明须要引用的库,使用 Packages get 进行拉取
编写 pubspec.yaml:
dependencies:
flutter:
sdk: flutter
cupertion_icons: ^0.1.0
dio: ^2.1.0
复制代码
调用:
import 'package:dio/dio.dart'; // Dio 一个很强大的网络请求库
void main() {
getHttp();
}
void getHttp() async {
try {
Response response = await Dio().get("http://www.baidu.com");
} catch (e) {
print(e);
}
}
复制代码
在上方的例子中咱们使用了 async 和 await ,你们能够自行预习,下篇文章应该会讲到
咱们先建立一个 mylib.dart
的文件,并写入如下内容,写啥都没关系,随便写
class MyLib {
String name;
static MyLib _cache;
factory MyLib([String name = 'singleton']) => MyLib._catch ??= MyLib._newObject(name);
MyLib._newObject(this.name);
}
复制代码
咱们在另外一个文件中引入 mylib.dart 文件, 我这里是同一级目录,因此直接这么引入哈
import 'mylib.dart';
void main() {
var myLib = MyLib(); // 实例化 mylib.dart 中的类
}
复制代码
若是两个库有冲突的标识符,能够为其中一个或两个库都指定前缀来避免冲突
假设咱们有 mylib1.dart
和 mylib2.dart
这两个文件都有一个名为 MyLib 的类
class MyLib() {
String name;
MyLib(this.name);
}
复制代码
这个时候咱们须要在一个地方同时引入这两个文件,并实例化 MyLib
import 'mylib1.dart';
import 'mylib2.dart';
void main() {
var myLib1 = MyLib();
var myLib2 = MyLib();
}
复制代码
不用我说了,你们看着都有问题,那咱们是否是能够指定一个前缀(别名) 呢, 在dart里可使用 as
来为引入的文件指定一个前缀
import 'mylib1.dart' as lib1;
import 'mylib2.dart' as lib2;
void main() {
var myLib1 = lib1.MyLib();
var myLib2 = lib2.MyLib();
}
复制代码
若是你只须要使用库的一部分功能,则能够选择须要导入的内容
import 'mylib1.dart' as lib1 show Test
import 'mylib2.dart' as lib2 hide Test
复制代码
使用 deferred as
导入,使用标识符调用 loadLibrary() 加载库
import 'mylib1.dart' deferred as lazyLib;
void main() {
lazyLoad()''
}
lazyLoad () async {
await lazyLib.loadLibrary();
var t = lazyLib.Test();
t.test();
}
复制代码
用 library 来来命名库,用part来指定库中的其余文
part 能够把一个库分开到多个 Dart 文件中
或者咱们想让某一些库共享它们的私有对象的时候,能够须要使用 part
import 不会彻底共享做用域,而 part 之间是彻底共享的。若是说在A库中import了B库,B库import了C库,A库是没有办法直接使用C库的对象的。而B,C如果A的part,那么三者共享全部对象。而且包含全部导入
注意:没必要在应用程序中(具备顶级main()函数的文件)使用library,但这样作可让你在多个文件中执行应用程序
// mylib/tool.dart
part of mylib;
void printTool() => print('tool')
复制代码
// mylib/util.dart
part of mylib;
void printUtil() => print('util');
复制代码
// mylib/mylib.dart
library mylib;
part 'util.dart';
part 'tool.dart';
void printMyLib() => print('mylib');
复制代码
import 'mylib/mylib.dart';
void main() {
printMyLib();
printUtil();
printTool();
}
复制代码
我的博客 能够根据博客右上角的 qq 图标直接联系我哈
通过这几篇文章的讲解,dart的基础已经差很少了,大概还有一两篇内容,dart 文章就要结束了,到时候开始带你们走进flutter的世界,谢谢你们,劳烦您的小手能够为我点个赞。讲的很差的地方也请留言给我提示,谢谢你们