總結:
記住構造函數是不能被繼承的,這將意味着子類不能繼承父類的命名式構造函數,如果你想在子類中提供一個與父類命名構造函數名字一樣的命名構造函數,則需要在子類中顯式地聲明
如果類A 沒有顯示聲明構造函數,那么它將有一個默認的構造函數,這個構造函數 沒有參數
如果這個類有父類,
a: 父類沒有顯示聲明構造函數,或者寫了一個普通無參構造
那么A構造函數(無論默認構造還是命名構造等),還會默認調用父類的無參數構造函數
b:父類顯示聲明構造函數
那么A類必須要有非默認構造函數(否則會把報錯),且必須顯示調用父類其中一個構造函數
1、默認構造函數
如果你定義了一個類,而沒有定義構造函數,那么它將有一個默認的構造函數,這個構造函數 沒有參數
如果這個類有父類,那么默認構造函數,還會默認調用父類的無參數構造函數。
如果自己寫了構造函數,那就會覆蓋默認構造(這個不存在了),
class People{
String peopleName;
People(String peopleName){
}
}
class Student extends People{
String studentName;
}
自己可以寫個同樣的無參構造進行覆蓋默認無參構造
class People{
String name;
int age;
int sex;
People(){
}
}
2、普通構造函數
聲明一個和類名相同的函數,來作為類的構造函數
class Person {
String name;
num age;
Person(String name, num age) {
this.name = name;
this.age = age;
}
}
Dart 中可以簡寫:
說明 普通構造函數不能重載,
並且子類必須顯示的調用
explicitly invokes a constructor 顯示的調用一個構造函數
3、命名構造函數
使用命名構造函數可為一個類實現多個構造函數,但是同樣不能重載
子類必須顯式的調用其中的一個
class Student extends People{
String studentName;
Student.studentinit() : super.init();
}
這里可以實現 構造函數的私有化 比如單例中的使用
4、調用父類構造函數
默認情況下,子類的構造函數會調用父類的匿名無參數構造方法,並且該調用會在子類構造函數的函數體代碼執行前,如果子類構造函數還有一個初始化列表,那么該初始化列表會在調用父類的該構造函數之前被執行,總的來說,這三者的調用順序如下:
- 初始化列表
- 父類的構造函數
- 當前類的構造函數
如果父類沒有匿名無參數構造函數,那么子類必須調用父類的其中一個構造函數,為子類的構造函數指定一個父類的構造函數只需在構造函數體前使用(:
)指定。
因為參數會在子類構造函數被執行前傳遞給父類的構造函數,因此該參數也可以是一個表達式,比如一個函數:
class Employee extends Person {
Employee() : super.fromJson(defaultData);
// ···
}
注意:
傳遞給父類構造函數的參數不能使用 this
關鍵字,因為在參數傳遞的這一步驟,子類構造函數尚未執行,子類的實例對象也就還未初始化,因此所有的實例成員都不能被訪問,但是類成員可以。
class Student extends People{
String studentName;
String studentAge;
String studentSex;
int age1
Student(
this.studentAge,
{
this.studentSex,
int age
}
):studentName = "1", this.age1 = age ?? 10, super(age);
}
不能同時在構造器和初始化列表中同時初始化,
下面是兩種不通過的寫法
class People{
String name;
int age;
int sex;
People(int age){
}
}
import 'People.dart';
class Student extends People {
String studentName;
String studentAge;
String studentSex;
String studentSex1;
Student(this.studentAge,
{
this.studentSex,
int age
})
:studentName = "1",
super(age);
Student.init(this.studentAge, {this.studentName: "22", this.studentSex1 = "33", int age})
: studentSex = "1",
super(age){
}
}
5. 構造函數傳遞(重定向構造函數)
定義構造函數的時候,除了一個普通構造函數,還可以有若干命名構造函數,這些構造函數之間,有時候會有一些相同的邏輯,如果分別書寫在各個構造函數中,會有些多余,所以構造函數可以傳遞。
class Point {
num x, y;
// The main constructor for this class.
Point(this.x, this.y);
// Delegates to the main constructor.
Point.alongXAxis(num x) : this(x, 0);
}
class Point {
num x, y,z;
// The main constructor for this class.
Point(this.x, this.y);
Point.aaa(this.x,this.y,this.z);
// Delegates to the main constructor.
Point.alongXAxis(num x):this.aaa(x,0,x);
}
復制代碼
傳遞構造函數,沒有方法體,會在初始化列表中,調用另一個構造函數。
6常量構造函數
class ImmutablePoint {
static final ImmutablePoint origin =
const ImmutablePoint(0, 0);
final num x, y;
const ImmutablePoint(this.x, this.y);
}
復制代碼
如果你的類,創建的對象永遠不會改變,你可以在編譯期就創建這個常量實例,並且定義一個常量構造函數,並且確保所有的成員變量都是final的。
7工廠構造函數的定義
工廠構造函數是一種構造函數,與普通構造函數不同,工廠函數不會自動生成實例,而是通過代碼來決定返回的實例對象.
使用 factory
關鍵字標識類的構造函數將會令該構造函數變為工廠構造函數,這將意味着使用該構造函數構造類的實例時並非總是會返回新的實例對象。例如,工廠構造函數可能會從緩存中返回一個實例,或者返回一個子類型的實例。
以下示例演示了從緩存中返回對象的工廠構造函數:
class Logger {
final String name;
bool mute = false;
// _cache 變量是庫私有的,因為在其名字前面有下划線。
static final Map<String, Logger> _cache =
<String, Logger>{};
factory Logger(String name) {
return _cache.putIfAbsent(
name, () => Logger._internal(name));
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
在工廠構造函數中無法訪問 this
。