前言:開發中碰到一個Java文件中有很多的成員變量,包括靜態和非靜態的,還有很多的初始化方法,很好奇這些成員的初始化順序,在這裡作個研究。
1 無繼承情況下的Java初始化順序:
class Sample {
Sample(String s) {
System.out.println(s);
}
Sample() {
System.out.println("Sample默認構造函數被調用");
}
}
class Test {
static Sample sam=new Sample("靜態成員sam初始化");
Sample sam1=new Sample("sam1成員初始化");
static {
System.out.println("static塊執行");
if(sam==null)System.out.println("sam is null");
sam=new Sample("靜態塊內初始化sam成員變量");
}
Test() {
System.out.println("Test默認構造函數被調用");
}
}
//主函數
public static void main(String str[]) {
Test a=new Test();
}
輸出結果為:
靜態成員sam初始化 -----靜態成員初始化
static塊執行 -----靜態塊被執行
靜態塊內初始化sam成員變量 -----靜態塊執行
sam1成員初始化 -----普通成員初始化
Test默認構造函數被調用 -----構造函數執行
由此可以得出初始化順序為:
a 靜態成員變量首先初始化(注意,Static可以看做一個靜態成員,其執行順序和其在類中申明的順序有關)
b 普通成員初始化
c 執行構造函數。
對於靜態成員(static塊可以看成普通的一個靜態成員,其並不一定在類初始化時首先執行)和普通成員,其初始化順序只與其在類定義中的順序有關,和其他因素無關。
例如下面的例子:
class Test {
static {
System.out.println("static 塊 1 執行");
}
static Sample staticSam1=new Sample("靜態成員staticSam1初始化");
Sample sam1=new Sample("sam1成員初始化");
static Sample staticSam2=new Sample("靜態成員staticSam2初始化");
static {
System.out.println("static 塊 2 執行");
}
Test() {
System.out.println("Test默認構造函數被調用");
}
Sample sam2=new Sample("sam2成員初始化");
}
則結果為:
static 塊 1 執行
靜態成員staticSam1初始化
靜態成員staticSam2初始化
static 塊 2 執行
------------------------------靜態成員
sam1成員初始化
sam2成員初始化
------------------------------普通成員
Test默認構造函數被調用
------------------------------構造函數
2 Java繼承情況下的初始化順序:
class Test {
static {
System.out.println("父類static 塊 1 執行");
}
static Sample staticSam1=new Sample("父類 靜態成員staticSam1初始化");
Sample sam1=new Sample("父類 sam1成員初始化");
static Sample staticSam2=new Sample("父類 靜態成員staticSam2初始化");
static {
System.out.println("父類 static 塊 2 執行");
}
Test() {
System.out.println("父類 Test默認構造函數被調用");
}
Sample sam2=new Sample("父類 sam2成員初始化");
}
class TestSub extends Test {
static Sample staticSamSub=new Sample("子類 靜態成員staticSamSub初始化");
TestSub() {
System.out.println("子類 TestSub 默認構造函數被調用");
}
Sample sam1=new Sample("子類 sam1成員初始化");
static Sample staticSamSub1=new Sample("子類 靜態成員staticSamSub1初始化");
static {System.out.println("子類 static 塊 執行");}
Sample sam2=new Sample("子類 sam2成員初始化");
}
執行結果:
父類 static 塊 1 執行
父類 靜態成員staticSam1初始化
父類 靜態成員staticSam2初始化
父類 static 塊 2 執行
--------------------------------父類靜態成員初始化
子類 靜態成員staticSamSub初始化
子類 靜態成員staticSamSub1初始化
子類 static 塊 執行
--------------------------------子類靜態成員初始化
父類 sam1成員初始化
父類 sam2成員初始化
父類 Test默認構造函數被調用
--------------------------------父類普通成員初始化和構造函數執行
子類 sam1成員初始化
子類 sam2成員初始化
子類 TestSub 默認構造函數被調用
--------------------------------父類普通成員初始化和構造函數執行
由此得出Java初始化順序為:
a 繼承體系的所有靜態成員初始化(先父類,後子類)
b父類初始化完成(普通成員的初始化-->構造函數的調用)
c 子類初始化(普通成員-->構造函數)
Java初始化順序如圖: