我們都知道要使用類,一般都需要先new出實例然后再使用。而類包含行為和狀態(tài),也有靜態(tài)非靜態(tài)之分。在使用實例的成員時候必須確保已經(jīng)分配資源。
java中將基本類型賦值為初始值,如int類型的賦值為0,引用類型的賦值為null。
那靜態(tài)成員、非靜態(tài)成員、構造函數(shù),這幾個的執(zhí)行順序如何?
靜態(tài) -> 非靜態(tài)成員 -> 構造函數(shù)
- 靜態(tài)成員在類第一次被訪問,實例化、觸摸任一靜態(tài)成員,的時候初始化且僅此一次
- 之所以要先初始化非靜態(tài)字段,是因為構造函數(shù)允許開發(fā)者改變其值
那如果B類繼承子A類, 實例化B,兩個類中的靜態(tài)/非靜態(tài)、構造函數(shù)的執(zhí)行順序又是如何?
父類靜態(tài)成員 -> 子類靜態(tài)成員 -> 父類非靜態(tài)成員 -> 父類構造函數(shù) -> 子類非靜態(tài)成員 -> 子類構造函數(shù)
繼承主要是為了復用父類資源,然后擴展特性操作;那么在實例化子類的時候就先要獲取到父類的實例,然后再實例化自身。這里要注意的是,子類的靜態(tài)成員初始化緊跟在父類靜態(tài)成員的初始化之后, 接著才是按照繼承體系 非靜態(tài)成員 -> 構造函數(shù) 這樣子的順序初始化; 當然, 在子類中也可以顯式地調(diào)用super改變
以下是執(zhí)行過程:
public class ClassLoadingOrder {
public static void main(String[] args) {
System.out.println("class loading start: ");
System.out.println();
Beetle beetle = new Beetle();
}
}
/**
* 父類 昆蟲
*/
class Insect {
// 私有字段
private int i = 9;
// 保護字段
protected int j;
// 私有靜態(tài)字段
private static int x1 = printInit("static Insect.x1 initialized");
// 構造函數(shù)
Insect() {
print("Insect start initializing");
print("i = " + i + ", j = " + j);
j = 39;
}
// 幫助方法
static int printInit(String s) {
print(s);
return 47;
}
static void print(String msg) {
System.out.println(msg);
}
}
/**
* 子類 甲蟲
*/
class Beetle extends Insect {
// 私有字段
private int k = printInit("Beetle.k initialized");
// 私有靜態(tài)字段
private static int x2 = printInit("static Beetle.x2 initialized");
// 構造函數(shù)
Beetle() {
print("Beetle start initializing");
print("k = " + k);
print("j = " + j);
}
}
輸出:
class loading start:
static Insect.x1 initialized
static Beetle.x2 initialized
Insect start initializing
i = 9, j = 0
Beetle.k initialized
Beetle start initializing
k = 47
j = 39