標籤:賦值 生命週期 pre 初始 代碼 因此 詳解 分析 init
在開始本部落格寫作之前請大家看一道經典的java面試題
public class StaticTest{
public static void main(String args[]){
staticFunction();
}
static StaticTest st = new StaticTest();
static{
System.out.println("1");
}
StaticTest(){
System.out.println("3");
System.out.println("a="+a+" b="+b);
}
public static void staticFunction(){
System.out.println("4");
}
{
System.out.println("2");
}
int a=100;
static int b=112;
}
最後的答案是:
2
3
a=100 b=0
1
對於這個執行結果是不是有些讓你大跌眼鏡呢?那麼現在本菜鳥就來分析分析:對於靜態成員變數和靜態代碼塊而言,初始化的順序是按照出現順序;當有父類靜態代碼塊或者父類靜態成員變數的時候,不管出現順序如何,先初始化父類的,
面試題詳解,從類的生命週期和對象的初始化來分析:
1.類的生命週期是:載入->驗證->準備->解析->初始化->使用->卸載,只有在準備階段和初始化階段才會涉及類變數的初始化和賦值,因此只針對這兩個階段進行分析;
2.類的準備階段需要做是為類變數分配記憶體並設定預設值,因此類變數st為null、b為0;(需要注意的是如果類變數是final在載入階段就已經完成了初始化,可以把b設定為final試試);
3.類的初始化階段需要做是執行類構造器(類構造器是編譯器收集所有靜態語句塊和類變數的指派陳述式按語句在源碼中的順序合并產生類構造器,對象的構造方法是init,類的構造方法是cinit,可以在堆棧資訊中看到),因此先執行第一條靜態變數的指派陳述式即st = new StaticTest (),此時會進行對象的初始化,對象的初始化是先初始化成員變數再執行構造方法,因此列印2->設定a為110->執行構造方法(列印3,此時a已經賦值為110,但是b只是設定了預設值0,並未完成賦值動作),等對象的初始化完成後繼續執行之前的類構造器的語句,接下來就詳細說下:
首先執行語句: static StaticTest st = new StaticTest();這個語句等價於static{StaticTest st = new StaticTest() },StaticTest st = new StaticTest(),這個會先執行StaticTest類的成員變數和構造代碼塊,所以會先執行{System.out.println("2");}這個構造代碼塊,得出結果2,然後執行 int a=100;這個語句。然後執行StaticTest (){}構造方法,列印出3,a=100 b=0,最後執行static{ System.out.println("1");這個靜態代碼塊,結果為1
Java的靜態變數,成員變數,靜態代碼塊,構造塊的載入順序