本片文章有點長,主要講了 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的世界,謝謝你們,勞煩您的小手能夠爲我點個贊。講的很差的地方也請留言給我提示,謝謝你們