Flutter 知識梳理 (Dart) - Dart 和 Java 有哪些不一樣?

在學習Dart的時候,會遇到一些Java中沒有的概念或者用法,這篇文章總結了DartJava中一些不一樣,但又常常會用到的知識點。html

1、構造函數初始化列表

初始化列表定義在構造函數){之間,初始化列表的語句之間用,分割,它的做用有以下幾點。java

1.1 爲final變量賦值

咱們但願類中的final變量初始值能由外部傳入,可是在構造函數中爲final變量賦值是不容許的,例以下面這樣:編程

class ConstField {
  
  final value;
  
  ConstField(int y) {
    value = y;
  }
  
}
複製代碼

此時能夠採用Dart提供的初始化列表的方式:ide

class ConstField {
  
  final value;
  
  ConstField(int input) : value = input;
  
}
複製代碼

只有初始化列表,沒有構造函數體的時候,初始化列表最後用;結尾。函數

1.2 對輸入參數進行判斷

class ConstField {
  
  final value;
  
  ConstField(int input) : assert(input > 0), value = input;
  
}
複製代碼

1.3 調用父類的構造函數

class Parent {
  
  int value;
  
  Parent(int input);
  
}

class Child extends Parent {
  
  Child(int input) : assert(input > 0), super(input);
  
}
複製代碼

在有初始化列表的狀況下,函數調用的前後順序爲:學習

  • 子類初始化列表
  • 父類構造函數
  • 子類構造函數

2、const 構造函數

const構造函數能夠保證你的類稱爲永遠不會更改的對象,並使這些對象稱爲編譯時常量:ui

  • 定義const構造函數確保全部實例變量都是final的。
  • 構造函數不能有函數體,可是能夠有初始化列表。
class ConstConstructor {
  
  final value;
  
  const ConstConstructor(int input) : value = input;
  
}
複製代碼

3、實例變量的賦值

3.1 使用this簡化賦值

class Subject {
  
  int value;
  int value2;
  
  Subject(this.value, this.value2);
  
  log() {
    print('value=$value, value2=$value2');
  }
  
}

void main() {
  Subject(2,3).log();
}
複製代碼

3.2 使用可選參數列表賦值或提供默認值

當咱們但願 只爲某些變量賦值,其他的採用初始值 時,在Java中只能採用定義多個構造函數或者使用builder模式,在Dart中採用可選參數列表的方式實現就很簡單,調用的時候只須要採用 參數名:值 的形式賦值便可。this

class Subject {
  
  int value;
  int value2;
  
  Subject({this.value, this.value2 = 3});
  
  log() {
    print('value=$value, value2=$value2');
  }
  
}

void main() {
  Subject(value : 2).log();
}
複製代碼

4、getter & setter

getset是專門用來讀取和寫入對象的屬性的方法,每個類的實例變量都有一個隱式的getter和可能的setterfinal或者const的只有getter)。spa

setter/getter使得咱們在外部能夠像對待普通成員變量進行操做,可是在內部進行額外的處理。.net

set/get後跟的是成員變量的名字,不能夠與其它成員變量重名。

class Person {
  
  String _name;
      
  set name(String value) {
    assert(value != null);
    _name = value;
  }
  
  get name => 'Person name is $_name';
  
}

void main() {
  Person p = Person();
  p.name = "tom";
  print(p.name);
}
複製代碼

5、factory 修飾的構造函數

factory 用於修飾類的構造函數

例如,咱們有一個Shape類,當咱們用factory修飾:

factory Shapre() { return ...; }
複製代碼

再經過Shape()或者new Shape()的方式調用該函數時,不會真正地建立Shape,而是由該構造函數返回一個Shape或者Shape的子類。

它至關於爲類提供了一個靜態的建立方法,該方法的返回值是它自己或它的子類對象,可是外部並不知道這個方法的存在,只須要按照普通建立對象的方式建立便可。

根據這一特色,目前factory的應用有兩類:

  • 實現工廠模式。
  • 單例模式。

5.1 工廠模式

Java中工廠模式的實現能夠參考這裏,工廠模式,下面咱們Dart的實現版本。

class Shape {
  
  factory Shape(String shapeType) {
    if (shapeType.compareTo('CIRCLE') == 0) {
      return Square();
    } else {
      return Circle();
    }
  }
  
  void draw() {}
}

class Square implements Shape {
  
  @override
  void draw() {
    print('Inside Square::draw() method.');
  }
}

class Circle implements Shape {
  
  @override
  void draw() {
    print('Inside Circle::draw() method.');
  }
}

void main() {
  Shape shape = Shape('CIRCLE');
  shape.draw();
}
複製代碼

5.2 單例模式

回想一下,在Java中實現單例模式時,通常會將它的構造方法聲明爲private,再定義一個getInstance()的靜態方法來返回單例對象。

而在Dart中,利用factory的特性,咱們能夠仍然按普通的方式建立對象,可是在多個地方得到的是同一個實例。

class Singleton {

  //單例對象。
  static Singleton _instance;

  //構造函數。
  Singleton._internal() {
    print("_internal");
  }

  static Singleton _getInstance() {
    //僅在 _instance 爲空時才調用。
    if (_instance == null) {
      _instance = Singleton._internal();
    }
    return _instance;
  }
  
  //調用方法。
  void method() {
    print("method");
  }

  //1.經過 new Singleton() 調用。
  factory Singleton() => _getInstance();
  //2.經過 Singleton.instance 調用。
  static Singleton get instance => _getInstance();

}
複製代碼

調用方式有以下兩種,_instance都會只建立一次:

Singleton.instance.method();
Singleton().method();
複製代碼

6、命名構造函數

Java中,能夠聲明多個構造函數,可是會遇到一個問題,若是有多個構造函數接受的參數個數和類型都相同,那怎麼辦呢?Dart的命名參數就解決了這一個問題。

除此以外,Dart的命名構造函數可使得含義更加直觀。

class Point {
  
  int x1;
  int y1;
  
  Point({this.x1, this.y1});
  
  Point.coordinate100() {
    x1 = 100;
    y1 = 100;
  }
    
  Point.coordinate50() {
    x1 = 50;
    y1 = 50;
  }
  
  log() {
    print('x=$x1, y=$y1');
  }
  
}

void main() {
  Point p100 = Point.coordinate100();
  p100.log();
  Point p50 = Point.coordinate50();
  p50.log();
}
複製代碼

這裏須要注意,當咱們聲明瞭命名構造函數,那麼就會 覆蓋默認的無參構造函數,這點和聲明瞭普通的有參構造函數是同樣的。也就是說,在它子類的構造函數中,須要經過super.xxx顯示地調用父類中的構造函數。

7、操做符

Dart中有一些操做符和Java不一樣。

7.1 類型操做符

  • 判斷對象是不是指定的類型,使用is或者!is,相似Java中的instanceof
void main() {
   int n = 2;
   print(n is int);
}

void main() {
   double  n = 2.20;
   var num = n is! int;
   print(num);
}
複製代碼
  • a as T:將a轉換稱爲指定的類型T,相似於Java中的(T)a

7.2 賦值運算符

  • ??=:僅在變量爲null時才分配。
void main() {
  int a;
  a ??= 1;
  a ??= 2;
  print(a);
}
複製代碼

運行結果:

1
複製代碼

7.3 條件表達式

  • expr1 ?? expr2:若是expr1不爲null,那麼返回expr1的值,不然返回expr2的值。
void main() {
  String a;
  String b = a ?? "default";
  print(b);
}
複製代碼

運行結果:

default
複製代碼

7.4 條件成員訪問:判空+調用

  • ?.:僅當對象不爲空時才執行後面的操做,省去了Java中先判空,再去調用方法的步驟。
class Person {
  
  String name;
  
  Person(this.name);
      
  log() {
    print(name);
  }
  
}

void main() {
  Person p;
  String name = p?.name;
  p?.log();
  p = Person('a');
  p.log();
}
複製代碼

7.5 級聯操做符

..容許對同一對象執行一系列操做,能夠省去建立臨時變量的步驟。

class Person {
  
  String name;
  
  Person(this.name);
      
  log() {
    print(name);
  }
  
}

void main() {
  Person p = Person('a');
  p..name = 'b'
    ..log();
}
複製代碼

8、函數也是一種類型

Flutter中,有不少將Function也就是方法做爲成員變量的使用,其做用相似於Java當中的回調,當咱們的回調接口中只有一個抽象函數時,可使用這種方法代替。

typedef CalBuilder = int Function(int x, int y);

class Cal {
  
  CalBuilder builder;
  
  Cal(this.builder);
      
  log() {
    print('result=${builder(1, 2)}');
  }
  
}

void main() {
  Cal cal = Cal((a, b) => a + b);
  cal.log();
}
複製代碼

9、函數的可選參數

當函數執行時不須要強制傳遞參數時,可使用可選參數,可選參數時函數中的最後一個參數。

9.1 可選位置參數

可選參數的語法爲:

void function_name(param1, [param1, param2]) { }
複製代碼

示例以下:

void main() {
  func(1);
  func(1,'2');
}

void func(int a, [String b, int c]) {
  print(a);
  print(b);
  print(c);
}
複製代碼

注意:若是當賦值給可選參數的實參數目不夠時,那麼必須按照形參類型定義的順序依次賦值,不然沒法編譯經過。

9.2 可選命名參數

與可選位置參數不一樣,可選命名參數要求必須在傳遞值時指定參數名稱。

void function_name(a, {param1, param2}) { }
複製代碼

示例:

void main() {
  func(1);
  func(2, c:3);
}

void func(int a, {String b, int c}) {
  print(a);
  print(b);
  print(c);
}
複製代碼

9.3 帶有默認值的可選參數

不管是可選位置參數仍是可選命名參數,均可以定義默認值。語法爲:

function_name(param1, {param2 = default_value}) { }
複製代碼

示例:

void main() {
  func(1);
  func(1,'2');
}

void func(int a, [String b = 'default', int c]) {
  print(a);
  print(b);
  print(c);
}
複製代碼

輸出結果:

1
default
null
1
2
null
複製代碼

10、容器

Dart中,經常使用的容器有ListMap,在使用上和Java也有一些區別。能夠參考下面的兩篇文章,就不列舉了:

參考文章

相關文章
相關標籤/搜索