Java中類的加載順序剖析(常用于面試題)
這其實是去年校招時我遇到的一道阿里巴巴的筆試題(承認(rèn)有點久遠(yuǎn)了-。-),嗯,如果我沒記錯的話,當(dāng)時是作為Java方向的一道選做大題。當(dāng)然題意沒有這么直白,題目只要求你寫出程序運行后所有System.out.println的輸出結(jié)果,其中程序是題目給的,而各個System.out.println的執(zhí)行順序不同會導(dǎo)致最后程序輸出的結(jié)果也不同。
具體的題目我肯定記不清,不過我們可以換個直接的問法,如果類A和類B中有靜態(tài)變量,靜態(tài)語句塊,非靜態(tài)變量,非靜態(tài)語句塊,構(gòu)造函數(shù),靜態(tài)方法,非靜態(tài)方法,同時類A繼承類B,請問當(dāng)實例化A時,類內(nèi)部的加載順序是什么?
當(dāng)時我也是一頭霧水,事后我就自己寫了一個小Demo,這才知道了類內(nèi)部的實際加載順,測試代碼如下:
Class B:
public class B{
//靜態(tài)變量
static int i=1;
//靜態(tài)語句塊
static {
System.out.println("Class B1:static blocks"+i);
}
//非靜態(tài)變量
int j=1;
//靜態(tài)語句塊
static{
i++;
System.out.println("Class B2:static blocks"+i);
}
//構(gòu)造函數(shù)
public B(){
i++;
j++;
System.out.println("constructor B: "+"i="+i+",j="+j);
}
//非靜態(tài)語句塊
{
i++;
j++;
System.out.println("Class B:common blocks"+"i="+i+",j="+j);
}
//非靜態(tài)方法
public void bDisplay(){
i++;
System.out.println("Class B:static void bDisplay(): "+"i="+i+",j="+j);
return ;
}
//靜態(tài)方法
public static void bTest(){
i++;
System.out.println("Class B:static void bTest(): "+"i="+i);
return ;
}
}
Class A:
public class A extends B{
//靜態(tài)變量
static int i=1;
//靜態(tài)語句塊
static {
System.out.println("Class A1:static blocks"+i);
}
//非靜態(tài)變量
int j=1;
//靜態(tài)語句塊
static{
i++;
System.out.println("Class A2:static blocks"+i);
}
//構(gòu)造函數(shù)
public A(){
super();
i++;
j++;
System.out.println("constructor A: "+"i="+i+",j="+j);
}
//非靜態(tài)語句塊
{
i++;
j++;
System.out.println("Class A:common blocks"+"i="+i+",j="+j);
}
//非靜態(tài)方法
public void aDisplay(){
i++;
System.out.println("Class A:static void aDisplay(): "+"i="+i+",j="+j);
return ;
}
//靜態(tài)方法
public static void aTest(){
i++;
System.out.println("Class A:static void aTest(): "+"i="+i);
return ;
}
}
Class ClassLoading :
public class ClassLoading {
public static void main (String args[]) {
A a=new A();
a.aDisplay();
}
}
程序運行結(jié)果如圖:

通過上述示圖,我們可以比較清晰的看出java類的整個加載過程。
1.若要加載類A,則先加載執(zhí)行其父類B(Object)的靜態(tài)變量以及靜態(tài)語句塊(執(zhí)行先后順序按排列的先后順序)。
2.然后再加載執(zhí)行類A的靜態(tài)變量以及靜態(tài)語句塊。(并且1、2步驟只會執(zhí)行1次)
3.若需實例化類A,則先調(diào)用其父類B的構(gòu)造函數(shù),并且在調(diào)用其父類B的構(gòu)造函數(shù)前,依次先調(diào)用父類B中的非靜態(tài)變量及非靜態(tài)語句塊.最后再調(diào)用父類B中的構(gòu)造函數(shù)初始化。
4.然后再依次調(diào)用類A中的非靜態(tài)變量及非靜態(tài)語句塊.最后調(diào)用A中的構(gòu)造函數(shù)初始化。( 并且3、4步驟可以重復(fù)執(zhí)行)
5.而對于靜態(tài)方法和非靜態(tài)方法都是被動調(diào)用,即系統(tǒng)不會自動調(diào)用執(zhí)行,所以用戶沒有調(diào)用時都不執(zhí)行,主要區(qū)別在于靜態(tài)方法可以直接用類名直接調(diào)用(實例化對象也可以),而非靜態(tài)方法只能先實例化對象后才能調(diào)用。
OK,今天就總結(jié)到這里了,如果有地方說的不好或有錯誤的地方,歡迎大家指出,定當(dāng)改正,謝謝。
相關(guān)文章
詳細(xì)解讀Druid數(shù)據(jù)庫連接池的使用
這篇文章主要介紹了Druid數(shù)據(jù)庫連接池的使用,數(shù)據(jù)庫連接池負(fù)責(zé)分配、管理和釋放數(shù)據(jù)庫連接,它允許應(yīng)用程序重復(fù)使用一個現(xiàn)有的數(shù)據(jù)庫連接,而不是重新建立一個,需要的朋友可以參考下2023-03-03
關(guān)于SpringMVC請求域?qū)ο蟮臄?shù)據(jù)共享問題
這篇文章主要介紹了SpringMVC請求域?qū)ο蟮臄?shù)據(jù)共享問題,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-02-02
SpringBoot統(tǒng)一功能處理示例詳解(攔截器)
這篇文章主要介紹了SpringBoot統(tǒng)一功能處理(攔截器),本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-08-08
劍指Offer之Java算法習(xí)題精講鏈表與數(shù)組專項訓(xùn)練
跟著思路走,之后從簡單題入手,反復(fù)去看,做過之后可能會忘記,之后再做一次,記不住就反復(fù)做,反復(fù)尋求思路和規(guī)律,慢慢積累就會發(fā)現(xiàn)質(zhì)的變化2022-03-03
mybatis中實現(xiàn)枚舉自動轉(zhuǎn)換方法詳解
在使用mybatis的時候經(jīng)常會遇到枚舉類型的轉(zhuǎn)換,下面這篇文章主要給大家介紹了關(guān)于mybatis中實現(xiàn)枚舉自動轉(zhuǎn)換的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧。2017-08-08

