// Dart中定義一個類
class Person {
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
}
複製代碼
Dart中的類與Java中的類似,不一樣的是,Dart中沒有private
、public
這些成員訪問修飾符。若是是類私有的成員,不但願外面訪問,只須要在成員變量以前加上一個下劃線_
變爲私有便可。html
以上代碼,在Dart中還有一種簡化寫法,能夠自動在構造方法中對成員變量初始化。git
// Dart中定義一個類
class Person {
String name;
int age;
// 在構造方法中初始化成員變量時,可以使用以下寫法簡化
Person(this.name, this.age);
// 如需處理其餘變量時,也可單獨對其操做
// Person(this.name, this.age, String address){
// print(address);
// }
// 注意,構造方法不能重載,以上註釋掉
}
複製代碼
另外還須要注意一點,Dart中沒有構造方法的重載,不能寫兩個同名的構造方法。github
在Java中,通常不會直接在類的外部去訪問類成員,一般使用setter和getter方法來操做類的成員變量。而在Dart語言中,全部類中都包含隱式的getter方法,對於非final
修飾的成員,類中還包含隱式的setter方法。這就意味着,在Dart中,你能夠直接在類外部經過.
操做符訪問類成員。這一特色使得Dart語法更加簡潔,不會寫出滿屏的setXXX、getXXX方法。web
固然,不少時候咱們調用setter和getter方法並不只僅是爲了賦值和訪問,而是爲了一些額外的處理,這時候咱們只須要使用set
與get
關鍵字實現setter和getter方法便可。編程
class Person {
String userName;
Person(this.userName);
// 方法名前加get關鍵字
String get name{
return "user:" + this.userName;
}
// 方法名前加set關鍵字
set name(String name){
// do something
this.userName = name;
}
}
void main() {
var p = new Person("zhangsan");
print(p.name); // user:zhangsan
p.name = "Jack";
print(p.name); // user:Jack
}
複製代碼
要注意,在建立對象時,new
關鍵字並非必須的,能夠省略不寫。在寫Flutter界面時,不建議寫new
關鍵字實例化對象,由於Flutter框架中沒有相似的xml語言來描述UI界面,界面也是使用Dart語言來寫,在使用Dart寫UI時,要保持代碼的簡潔和結構化,省略new
會更友好。緩存
若是沒有定義構造方法,則會有一個默認的無參構造方法,而且會調用超類的無參構造方法。bash
上面已經說過,Dart類中兩個同名構造方法不能重載,可是Dart語言爲類新增了一種稱爲命名構造方法
的東西。多線程
class Person {
String userName;
int age;
Person(this.userName, this.age);
// 命名構造方法
Person.fromData(Map data) {
this.userName = data['name'];
this.age = data['age'];
}
}
void main() {
// 使用命名構造方法建立對象
var p = new Person.fromData({
"name":"Bob",
"age":19
});
print(p.userName);
}
複製代碼
注意,使用命名構造方法能夠爲一個類實現多個構造方法,也能夠更清晰的代表意圖。框架
若是想提供一個狀態永遠不變的對像,在Dart中,咱們能夠建立一個編譯時常量對象,節省開銷。異步
class ConstPoint {
final num x;
final num y;
// 使用const修構造方法
const ConstPoint(this.x, this.y);
// 編譯時常量對象,需使用const來建立對象
static final ConstPoint origin = const ConstPoint(0, 0);
}
void main() {
print(ConstPoint.origin.x);
print(ConstPoint.origin.y);
}
複製代碼
當咱們須要建立一個新的對象或者從緩存中取一個對象時,工廠構造方法就派上了用場。
class Logger {
final String name;
// 建立一個靜態Map作爲緩存
static final Map<String, Logger> _cache = <String, Logger>{};
// 定義一個命名構造方法,用下劃線"_"修飾,將構造方法私有化
Logger._internal(this.name);
// 使用關鍵字factory修飾類同名構造方法
factory Logger(String name) {
if (_cache.containsKey(name)) {
return _cache[name];
} else {
// 調用命名構造方法建立新對象
final logger= new Logger._internal(name);
_cache[name] = logger; // 存入緩存
return logger;
}
}
}
void main() {
var uiLog = new Logger('UI');
var eventLog = new Logger('event');
}
複製代碼
有時候一個構造方法會調動類中的其餘構造方法來實例化,這時候可使用構造方法重定向,
class Point {
num x;
num y;
// 同名構造方法
Point(this.x, this.y);
// 命名構造方法重定向到同名構造方法,中間使用一個冒號
Point.alongXAxis(num x) : this(x, 0);
}
複製代碼
熟悉C++的朋友應該對初始化列表很瞭解了,Java中是沒有這個特性的。
class Point {
final num x;
final num y;
final num distance;
Point(x, y)
: x = x,
y = y,
distance = sqrt(x * x + y * y){
print("這是構造方法");
}
}
void main() {
var p = new Point(2, 3);
print(p.distance);
}
複製代碼
final
修飾的變量this
的這個特性,又很相似於C++中的運算符重載,在Java中是沒用這種概念的。
class Point {
int x;
int y;
Point(this.x, this.y);
// 使用operator關鍵字,爲該類重載"+"運算符
Point operator +(Point p) {
return new Point(this.x + p.x, this.y + p.y);
}
// 爲該類重載"-"運算符
Point operator -(Point p) {
return new Point(this.x - p.x, this.y - p.y);
}
}
void main(){
var p1 = new Point(1,5);
var p2 = new Point(7,10);
// 重載運算符後,類可使用「+」、「-」 運算符操做
var p3 = p1 + p2;
var p4 = p2 - p1;
print("${p3.x}, ${p3.y}");
print("${p4.x}, ${p4.y}");
}
複製代碼
打印結果:
8, 15
6, 5
複製代碼
Dart中容許重載的運算符以下:
+ |
– |
* |
~/ |
/ |
% |
^ |
< |
> |
<= |
>= |
== |
[] |
[]= |
& |
~ |
<< |
>> |
| |
Dart中的繼承,與Java中類似,可使用關鍵字extends
繼承父類,使用關鍵字super
引用父類
class Father {
myFunction(){
// do something
}
}
class Son extends Father {
@override
myFunction(){
super.myFunction();
// do something
}
}
複製代碼
咱們都知道,Java中的類僅支持單繼承,而Dart中的類能夠實現多繼承。要實現多繼承,須要使用with
關鍵字。
// 首先定義三個父類
class Father1 {
a(){
print("this is a func");
}
common(){
print("common Father1");
}
}
class Father2 {
b(){
print("this is b func");
}
common(){
print("common Father2");
}
}
class Father3 {
c(){
print("this is c func");
}
common(){
print("common Father3");
}
}
//定義子類
class Son extends Father1 with Father2,Father3{
}
void main() {
var obj = new Son();
obj.common();
obj.a();
obj.b();
obj.c();
}
複製代碼
打印結果:
common Father3
this is a func
this is b func
this is c func
複製代碼
要注意,以上繼承寫法中,也能夠直接使用with
,等價於以下寫法
class Son with Father1,Father2,Father3{
}
複製代碼
Dart語言沒有提供
interface
關鍵字來定義接口,可是Dart語言中保留了抽象類,同Java,使用abstract
關鍵字來修飾抽象類。而Dart中的抽象類,實際上就至關於Java中的接口。
abstract class Base {
// 省略函數體便可定義抽象方法,不需加關鍵字
func1();
func2();
}
複製代碼
注意,抽象類是不能被實例化的,子類繼承抽象類時,必須實現所有抽象方法。
實際上在Dart中,每一個類都隱式的定義了一個包含全部實例成員的接口, 而且該類實現了這個接口。
所以,若是咱們想實現某個接口,但有又不想繼承,則可使用這種隱式接口機制。咱們須要用到關鍵字implements
class People {
void greet(){
print("Hello");
}
}
class Student implements People{
@override
void greet(){
print("Hi,I'm Alice.");
}
}
greet(People p){
p.greet();
}
void main() {
greet(new Student());
}
複製代碼
Dart中也支持泛型,用法與Java中相似。
// 泛型
var names = new List<String>();
names.add("zhangsan")
var maps = new Map<int, String>();
maps[1]="value";
// 字面量寫法
var infos = <String>['Seth', 'Kathy', 'Lars'];
var pages = <String, String>{
'index.html': 'Homepage',
'robots.txt': 'Hints for web robots'
};
複製代碼
若是關心具體異常,針對不一樣異常進行不一樣處理,可使用try...on
處理異常,finally
是可選的,用於最後的處理。
try {
// 使除數爲0
print(11~/0);
} on IntegerDivisionByZeroException {
print("除數爲0");
}on Exception{
print("Exception");
}finally {
print("finally");
}
複製代碼
不關心具體異常,只想捕獲,避免異常繼續傳遞,則可使用try...catch
處理
try {
print(11~/0);
} catch(e){
// 打印報錯信息
print(e);
}finally {
print("finally");
}
複製代碼
若是想獲取更多異常信息,可使用兩個參數的catch
,第二個參數是異常的調用棧信息
try {
print(11~/0);
} catch(e,s){
print(s);
}
複製代碼
若是你既想針對不一樣異常進行不一樣處理,還想打印調用棧信息,那就將兩種結合起來使用
try {
print(11~/0);
} on IntegerDivisionByZeroException catch(e,s){
print(s);
} on Exception catch(e,s){
print(s);
}
複製代碼
Dart使用import
語句用來導入一個庫,後面跟一個字符串形式的Uri來指定表示要引用的庫。
// 指定dart:前綴,表示導入標準庫,如dart:io
import 'dart:math';
// 也能夠用相對路徑或絕對路徑來引用dart文件
import 'lib/student/student.dart';
// 指定package:前綴,表示導入包管理系統中的庫
import 'package:utils/utils.dart';
複製代碼
導入庫時,可使用as
關鍵字來給庫起別名,避免命名空間衝突。
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;
// 使用lib1中的Element
Element element1 = new Element();
// 使用lib2中的Element
lib2.Element element2 = new lib2.Element();
複製代碼
使用show
和hide
關鍵字控制庫中成員的可見性
// 僅導入foo,屏蔽庫中其餘成員
import 'package:lib1/lib1.dart' show foo;
// 屏蔽foo,庫中其餘成員均可見
import 'package:lib2/lib2.dart' hide foo;
複製代碼
爲了減小 APP 的啓動時間,加載不多使用的功能,咱們還能夠延遲導入庫。使用 deferred as
關鍵字延遲導入
import 'package:deferred/hello.dart' deferred as hello;
// 當須要使用時,再經過庫標識符調用 loadLibrary函數加載
hello.loadLibrary();
複製代碼
Dart與JavaScript同樣,是一個單線程模型。但這並不意味着Dart中不能進行異步編程,只是這種異步編程區別於傳統的多線程異步方式。
Dart中的全部代碼都只在一個線程上運行,但Dart代碼能夠運行在多個isolate上。isolate能夠看作一個微小的線程,isolate由虛擬機調度,isolate之間沒有共享內存,所以它們之間沒有競爭,不須要鎖,不用擔憂死鎖,所以開銷小,性能高。因爲沒有共享內存,因此它們之間惟一的通訊只能經過Port進行,並且Dart中的消息傳遞也老是異步的。
Dart中兩種方式可使用Future
對象來進行異步編程
async
和 await
關鍵字使用async
和await
編寫代碼很是簡單,並且編寫的代碼看起來有點像同步代碼,其實是異步的。
// 導入io庫,調用sleep函數
import 'dart:io';
// 模擬耗時操做,調用sleep函數睡眠2秒
doTask() async{
await sleep(const Duration(seconds:2));
return "Ok";
}
// 定義一個函數用於包裝
test() async {
var r = await doTask();
print(r);
}
void main(){
print("main start");
test();
print("main end");
}
複製代碼
運行結果:
main start
main end
Ok
複製代碼
在函數簽名中加入async
關鍵字,表示該函數異步執行,await
表示等待異步結果執行完成返回Future
對象。但有一點須要注意,await
只能在async
函數中出現,所以每每須要再定義一個async
函數,用於包裝。上述代碼中test
函數就是用於包裝。
關於Dart異步編程的更多詳細知識,請跳轉本人另外一篇博客 Dart 異步編程詳解之一文全懂
以上是本篇的所有內容,關於博主的更多技術文章,請跳轉到如下連接,謝謝!
GitHub