Java——物件初始化順序
阿新 • • 發佈:2019-02-08
一、 程式碼塊的概念
在探究物件初始化順序之前,我們先通過程式碼來了解一下程式碼塊的概念。
class Test{
public static String str1; //靜態欄位
public String str2; //普通欄位
static{
//靜態程式碼塊
}
{
//構造程式碼塊
}
public Test() {
//建構函式
}
}
二、 建立子類物件時,物件的初始化順序
1. 欄位初始化、程式碼塊和建構函式的執行順序
我們先看程式碼和結果
public class CodeBlockTest {
public static void main(String[] args) {
Child child = new Child();
}
}
class Father {
public static String fatherStr1 = "fatherStr1(靜態欄位初始化值)";
public String fatherStr2 = "fatherStr2(欄位初始化值)";
static {
System.out.println("父類靜態程式碼塊:" + fatherStr1);
fatherStr1 = "fatherStr1(靜態程式碼塊賦值)";
}
{
System.out.println("父類構造程式碼塊:" + fatherStr2);
fatherStr2 = "fatherStr2(構造程式碼塊賦值)";
}
public Father() {
System.out.println("父類建構函式塊:" + fatherStr2);
fatherStr2 = "fatherStr2(建構函式賦值)";
}
}
class Child extends Father {
public static String childStr1 = "childStr1(靜態欄位初始化值)";
public String childStr2 = "childStr2(欄位初始化值)";
static {
System.out.println("子類靜態程式碼塊:" + childStr1);
childStr1 = "childStr1(靜態程式碼塊賦值)";
}
{
System.out.println("子類構造程式碼塊:" + childStr2);
childStr2 = "childStr2(構造程式碼塊賦值)";
}
public Child() {
System.out.println("子類建構函式:" + childStr2);
childStr2 = "childStr2(建構函式賦值)";
}
}
// 輸出結果:
// 父類靜態程式碼塊:fatherStr1(靜態欄位初始化值)
// 子類靜態程式碼塊:childStr1(靜態欄位初始化值)
// 父類構造程式碼塊:fatherStr2(欄位初始化值)
// 父類建構函式塊:fatherStr2(構造程式碼塊賦值)
// 子類構造程式碼塊:childStr2(欄位初始化值)
// 子類建構函式:childStr2(構造程式碼塊賦值)
通過每執行一個程式碼塊或建構函式,輸出欄位在上一程式碼塊執行後的值,以此來探究物件的初始化順序。
由目前的輸出結果可知,對於物件的初始化順序,我們可以得出以下結論:
1. 父類靜態欄位初始化
2. 父類靜態程式碼塊、子類靜態欄位初始化 (接下來探究兩者的順序)
3. 子類靜態程式碼塊
4. 父類普通欄位初始化
5. 父類構造程式碼塊
6. 父類建構函式
7. 子類普通欄位初始化
8. 子類構造程式碼塊
9. 子類建構函式
2. 父類靜態程式碼塊和子類靜態欄位初始化的執行順序
還是一樣,我們通過程式碼的執行結果來探究兩者間的執行順序。
public class CodeBloacTest2 {
public static void main(String[] args) {
Child child = new Child();
}
}
class Father {
public static String fatherStr = "(靜態欄位初始化值)";
static {
System.out.println("父類靜態程式碼塊:fatherStr" + fatherStr);
fatherStr = "(靜態程式碼塊賦值)";
}
}
class Child extends Father {
public static String childStr = fatherStr;
static {
System.out.println("子類靜態程式碼塊:childStr = fatherStr" + childStr);
childStr = "(靜態程式碼塊賦值)";
}
}
// 輸出結果:
// 父類靜態程式碼塊:fatherStr(靜態欄位初始化值)
// 子類靜態程式碼塊:childStr = fatherStr(靜態程式碼塊賦值)
我們在子類靜態欄位childStr
初始化的時候,賦的是父類靜態欄位fatherStr
的值。由輸出結果可知,childStr
初始化後的值是父類靜態程式碼塊執行後賦予fatherStr
的值。由此可知兩者的執行順序為:父類靜態程式碼塊==>子類靜態欄位初始化
三、 結論
- 父類靜態欄位初始化
- 父類靜態程式碼塊
- 子類靜態欄位初始化
- 子類靜態程式碼塊
- 父類普通欄位初始化
- 父類構造程式碼塊
- 父類建構函式
- 子類普通欄位初始化
- 子類構造程式碼塊
- 子類建構函式
通過結論我們可以很明顯的看出:static欄位、程式碼塊的執行順序優先於非static欄位、程式碼塊。這是因為在靜態域是屬於類的,在類載入後就一直存在;而普通域需要建立物件才能訪問。而在建立物件時,需要先載入父類,然後再載入子類,因此父類的靜態欄位初始化和靜態程式碼塊執行先於子類。