在開始本博客寫作之前請大家看一道經典的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