Flutter學習之Dart語法(三)

本文首發於我的博客html

類和對象

Dart是一個面向對象的語言,面向對象中很是重要的概念就是類,類產生了對象。git

類的定義

在Dart中,定義類用class關鍵字。 類一般有兩部分組成:成員(member)和方法(method)。 定義類的僞代碼以下:github

class 類名 {
  類型 成員名;
  返回值類型 方法名(參數列表) {
    方法體
  }
}
複製代碼

編寫一個簡單的Person類:bash

  • 這裏有一個注意點: 咱們在方法中使用屬性(成員/實例變量)時,並無加this;
  • Dart的開發風格中,在方法中一般使用屬性時,會省略this,可是有命名衝突時,this不能省略;
class Person {
  String name;

  eat() {
    print('$name在吃東西');
  }
}
複製代碼

咱們來使用這個類,建立對應的對象:ide

  • 注意:從Dart2開始,new關鍵字能夠省略。
main(List<String> args) {
  // 1.建立類的對象
  var p = new Person(); // 直接使用Person()也能夠建立

  // 2.給對象的屬性賦值
  p.name = 'eagle';

  // 3.調用對象的方法
  p.eat();
}

複製代碼

構造方法

普通構造方法

咱們知道, 當經過類建立一個對象時,會調用這個類的構造方法。函數

  • 當類中沒有明確指定構造方法時,將默認擁有一個無參的構造方法。
  • 前面的Person中咱們就是在調用這個構造方法.

咱們也能夠根據本身的需求,定義本身的構造方法:學習

**注意一:**當有了本身的構造方法時,默認的構造方法將會失效,不能使用優化

  • 固然,你可能但願明確的寫一個默認的構造方法,可是會和咱們自定義的構造方法衝突;
  • 這是由於Dart自己不支持函數的重載(名稱相同, 參數不一樣的方式)。

**注意二:**這裏我還實現了toString方法ui

class Person {
  String name;
  int age;

  Person(String name, int age) {
    this.name = name;
    this.age = age;
  }

  @override
  String toString() {
    return 'name=$name age=$age';
  }
}
複製代碼

另外,在實現構造方法時,一般作的事情就是經過參數給屬性賦值 爲了簡化這一過程, Dart提供了一種更加簡潔的語法糖形式. 上面的構造方法能夠優化成下面的寫法:this

Person(String name, int age) {
    this.name = name;
    this.age = age;
  }
  // 等同於
  Person(this.name, this.age);

複製代碼

命名構造方法

可是在開發中, 咱們確實但願實現更多的構造方法,怎麼辦呢?

由於不支持方法(函數)的重載,因此咱們沒辦法建立相同名稱的構造方法。

咱們須要使用命名構造方法:

class Person {
  String name;
  int age;

  Person() {
    name = '';
    age = 0;
  }
	// 命名構造方法
  Person.withArgments(String name, int age) {
    this.name = name;
    this.age = age;
  }

  @override
  String toString() {
    return 'name=$name age=$age';
  }
}

// 建立對象
var p1 = new Person();
print(p1);
var p2 = new Person.withArgments('eagle', 18);
print(p2);

複製代碼

在以後的開發中, 咱們也能夠利用命名構造方法,提供更加便捷的建立對象方式:

好比開發中,咱們須要常常將一個Map轉成對象,能夠提供以下的構造方法

// 新的構造方法
	Person.fromMap(Map<String, Object> map) {
    this.name = map['name'];
    this.age = map['age'];
  }

	// 經過上面的構造方法建立對象
  var p3 = new Person.fromMap({'name': 'kobe', 'age': 30});
  print(p3);

複製代碼

初始化列表

咱們來從新定義一個類Point, 傳入x/y,能夠獲得它們的距離distance:

class Point {
  final num x;
  final num y;
  final num distance;

  // 錯誤寫法
  // Point(this.x, this.y) {
  //   distance = sqrt(x * x + y * y);
  // }

  // 正確的寫法
  Point(this.x, this.y) : distance = sqrt(x * x + y * y);
}

複製代碼

上面這種初始化變量的方法, 咱們稱之爲初始化列表(Initializer list)

重定向構造方法

在某些狀況下, 咱們但願在一個構造方法中去調用另一個構造方法, 這個時候可使用重定向構造方法:

在一個構造函數中,去調用另一個構造函數(注意:是在冒號後面使用this調用)

class Person {
  String name;
  int age;

  Person(this.name, this.age);
  Person.fromName(String name) : this(name, 0);
}

複製代碼

常量構造方法

在某些狀況下,傳入相同值時,咱們但願返回同一個對象,這個時候,可使用常量構造方法. 默認狀況下,建立對象時,即便傳入相同的參數,建立出來的也不是同一個對象,看下面代碼:

這裏咱們使用identical(對象1, 對象2)函數來判斷兩個對象是不是同一個對象:

main(List<String> args) {
  var p1 = Person('eagle');
  var p2 = Person('eagle');
  print(identical(p1, p2)); // false
}

class Person {
  String name;

  Person(this.name);
}

複製代碼

可是, 若是將構造方法前加const進行修飾,那麼能夠保證同一個參數,建立出來的對象是相同的

這樣的構造方法就稱之爲常量構造方法。

main(List<String> args) {
  var p1 = const Person('eagle');
  var p2 = const Person('eagle');
  print(identical(p1, p2)); // true
}

class Person {
  final String name;

  const Person(this.name);
}

複製代碼

常量構造方法有一些注意點:

  • 注意一:擁有常量構造方法的類中,全部的成員變量必須是final修飾的.
  • 注意二: 爲了能夠經過常量構造方法,建立出相同的對象,再也不使用 new關鍵字,而是使用const關鍵字

若是是將結果賦值給const修飾的標識符時,const能夠省略.

工廠構造方法

Dart提供了factory關鍵字, 用於經過工廠去獲取對象

main(List<String> args) {
  var p1 = Person('eagle');
  var p2 = Person('eagle');
  print(identical(p1, p2)); // true
}

class Person {
  String name;

  static final Map<String, Person> _cache = <String, Person>{};

  factory Person(String name) {
    if (_cache.containsKey(name)) {
      return _cache[name];
    } else {
      final p = Person._internal(name);
      _cache[name] = p;
      return p;
    }
  }

  Person._internal(this.name);
}

複製代碼

setter和getter

默認狀況下,Dart中類定義的屬性是能夠直接被外界訪問的。 可是某些狀況下,咱們但願監控這個類的屬性被訪問的過程,這個時候就可使用setter和getter了

main(List<String> args) {
  final d = Dog("黃色");
  d.setColor = "黑色";
  print(d.getColor);
}

class Dog {
  String color;

  String get getColor {
    return color;
  }
  set setColor(String color) {
    this.color = color;
  }

  Dog(this.color);
}

複製代碼

類的繼承

面向對象的其中一大特性就是繼承,繼承不只僅能夠減小咱們的代碼量,也是多態的使用前提。 Dart中的繼承使用extends關鍵字,子類中使用super來訪問父類。 父類中的全部成員變量和方法都會被繼承,,可是構造方法除外。

main(List<String> args) {
  var p = new Person();
  p.age = 18;
  p.run();
  print(p.age);
}

class Animal {
  int age;

  run() {
    print('在奔跑ing');
  }
}

class Person extends Animal {

}

複製代碼

子類能夠擁有本身的成員變量, 而且能夠對父類的方法進行重寫:

class Person extends Animal {
  String name;

  @override
  run() {
    print('$name在奔跑ing');
  }
}

複製代碼

子類中能夠調用父類的構造方法,對某些屬性進行初始化:

子類的構造方法在執行前,將隱含調用父類的無參默認構造方法(沒有參數且與類同名的構造方法)。 若是父類沒有無參默認構造方法,則子類的構造方法必須在初始化列表中經過super顯式調用父類的某個構造方法。

class Animal {
  int age;

  Animal(this.age);

  run() {
    print('在奔跑ing');
  }
}

class Person extends Animal {
  String name;

  Person(String name, int age) : name=name, super(age);

  @override
  run() {
    print('$name在奔跑ing');
  }

  @override
  String toString() {
    return 'name=$name, age=$age';
  }
}

複製代碼

抽象類

咱們知道,繼承是多態使用的前提。 因此在定義不少通用的調用接口時, 咱們一般會讓調用者傳入父類,經過多態來實現更加靈活的調用方式。 可是,父類自己可能並不須要對某些方法進行具體的實現,因此父類中定義的方法,,咱們能夠定義爲抽象方法。 什麼是 抽象方法? 在Dart中沒有具體實現的方法(沒有方法體),就是抽象方法。

抽象方法,必須存在於抽象類中。 抽象類是使用abstract聲明的類。

下面的代碼中, Shape類就是一個抽象類, 其中包含一個抽象方法.

abstract class Shape {
  getArea();
}

class Circle extends Shape {
  double r;

  Circle(this.r);

  @override
  getArea() {
    return r * r * 3.14;
  }
}

class Reactangle extends Shape {
  double w;
  double h;

  Reactangle(this.w, this.h);

  @override
  getArea() {
    return w * h;
  }
}

複製代碼

注意事項:

**注意一:**抽象類不能實例化. **注意二:**抽象類中的抽象方法必須被子類實現, 抽象類中的已經被實現方法, 能夠不被子類重寫.

隱式接口

Dart中的接口比較特殊, 沒有一個專門的關鍵字來聲明接口. 默認狀況下,定義的每一個類都至關於默認也聲明瞭一個接口,能夠由其餘的類來實現(由於Dart不支持多繼承) 在開發中,咱們一般將用於給別人實現的類聲明爲抽象類:

abstract class Runner {
  run();
}

abstract class Flyer {
  fly();
}

class SuperMan implements Runner, Flyer {
  @override
  run() {
    print('超人在奔跑');
  }

  @override
  fly() {
    print('超人在飛');
  }
}

複製代碼

Mixin混入

在經過implements實現某個類時,類中全部的方法都必須被從新實現(不管這個類原來是否已經實現過該方法)。 可是某些狀況下,一個類可能但願直接複用以前類的原有實現方案,怎麼作呢?

使用繼承嗎?可是Dart只支持單繼承,那麼意味着你只能複用一個類的實現。

Dart提供了另一種方案: Mixin混入的方式

除了能夠經過class定義類以外,也能夠經過mixin關鍵字來定義一個類。 只是經過mixin定義的類用於被其餘類混入使用,經過with關鍵字來進行混入。

main(List<String> args) {
  var superMan = SuperMain();
  superMan.run();
  superMan.fly();
}

mixin Runner {
  run() {
    print('在奔跑');
  }
}

mixin Flyer {
  fly() {
    print('在飛翔');
  }
}

// implements的方式要求必須對其中的方法進行從新實現
// class SuperMan implements Runner, Flyer {}

class SuperMain with Runner, Flyer {

}

複製代碼

類成員和方法

前面咱們在類中定義的成員和方法都屬於對象級別的, 在開發中, 咱們有時候也須要定義類級別的成員和方法 在Dart中咱們使用static關鍵字來定義:

main(List<String> args) {
  var stu = Student();
  stu.name = 'eagle';
  stu.sno = 110;
  stu.study();

  Student.time = '早上8點';
  // stu.time = '早上9點'; 錯誤作法, 實例對象不能訪問類成員
  Student.attendClass();
  // stu.attendClass(); 錯誤作法, 實現對象補鞥呢訪問類方法
}

class Student {
  String name;
  int sno;

  static String time;

  study() {
    print('$name在學習');
  }

  static attendClass() {
    print('去上課');
  }
}

複製代碼

枚舉類型

枚舉在開發中也很是常見, 枚舉也是一種特殊的類, 一般用於表示固定數量的常量值。

枚舉的定義

枚舉使用enum關鍵字來進行定義:

main(List<String> args) {
  print(Colors.red);
}

enum Colors {
  red,
  green,
  blue
}

複製代碼

枚舉的屬性

枚舉類型中有兩個比較常見的屬性:

index: 用於表示每一個枚舉常量的索引, 從0開始. values: 包含每一個枚舉值的List.

main(List<String> args) {
  print(Colors.red.index);
  print(Colors.green.index);
  print(Colors.blue.index);

  print(Colors.values);
}

enum Colors {
  red,
  green,
  blue
}

複製代碼

枚舉類型的注意事項:

  • 注意一: 您不能子類化、混合或實現枚舉。
  • 注意二: 不能顯式實例化一個枚舉

參考 ke.qq.com/course/4697…

相關文章
相關標籤/搜索