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

通過(guò)上述示圖,我們可以比較清晰的看出java類(lèi)的整個(gè)加載過(guò)程。
1.若要加載類(lèi)A,則先加載執(zhí)行其父類(lèi)B(Object)的靜態(tài)變量以及靜態(tài)語(yǔ)句塊(執(zhí)行先后順序按排列的先后順序)。
2.然后再加載執(zhí)行類(lèi)A的靜態(tài)變量以及靜態(tài)語(yǔ)句塊。(并且1、2步驟只會(huì)執(zhí)行1次)
3.若需實(shí)例化類(lèi)A,則先調(diào)用其父類(lèi)B的構(gòu)造函數(shù),并且在調(diào)用其父類(lèi)B的構(gòu)造函數(shù)前,依次先調(diào)用父類(lèi)B中的非靜態(tài)變量及非靜態(tài)語(yǔ)句塊.最后再調(diào)用父類(lèi)B中的構(gòu)造函數(shù)初始化。
4.然后再依次調(diào)用類(lèi)A中的非靜態(tài)變量及非靜態(tài)語(yǔ)句塊.最后調(diào)用A中的構(gòu)造函數(shù)初始化。( 并且3、4步驟可以重復(fù)執(zhí)行)
5.而對(duì)于靜態(tài)方法和非靜態(tài)方法都是被動(dòng)調(diào)用,即系統(tǒng)不會(huì)自動(dòng)調(diào)用執(zhí)行,所以用戶(hù)沒(méi)有調(diào)用時(shí)都不執(zhí)行,主要區(qū)別在于靜態(tài)方法可以直接用類(lèi)名直接調(diào)用(實(shí)例化對(duì)象也可以),而非靜態(tài)方法只能先實(shí)例化對(duì)象后才能調(diào)用。
OK,今天就總結(jié)到這里了,如果有地方說(shuō)的不好或有錯(cuò)誤的地方,歡迎大家指出,定當(dāng)改正,謝謝。
相關(guān)文章
Java Spring循環(huán)依賴(lài)原理與bean的生命周期圖文案例詳解
這篇文章主要介紹了Spring循環(huán)依賴(lài)原理與bean的生命周期圖文案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-09-09
jetty運(yùn)行時(shí)無(wú)法保存文件的解決方法
這篇文章主要為大家詳細(xì)介紹了jetty運(yùn)行時(shí)無(wú)法保存文件的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11
關(guān)于Spring源碼是如何解決Bean的循環(huán)依賴(lài)
這篇文章主要介紹了關(guān)于Spring源碼是如何解決Bean的循環(huán)依賴(lài),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
Spring?Cloud?Alibaba?Nacos兩種檢查機(jī)制
這篇文章主要介紹了Spring?Cloud?Alibaba?Nacos兩種檢查機(jī)制,作為注冊(cè)中心不止提供了服務(wù)注冊(cè)和服務(wù)發(fā)現(xiàn)功能,它還提供了服務(wù)可用性監(jiān)測(cè)的機(jī)制,下面我們就一起進(jìn)入文章了解具體詳情吧2022-05-05
java設(shè)計(jì)模式之觀(guān)察者模式簡(jiǎn)單解讀
這篇文章主要介紹了java設(shè)計(jì)模式之觀(guān)察者模式簡(jiǎn)單解讀,觀(guān)察者模式是在對(duì)象之間定義了一對(duì)多的依賴(lài),這樣一來(lái),當(dāng)一個(gè)對(duì)象改變狀態(tài),依賴(lài)它的對(duì)象會(huì)收到通知并自動(dòng)更新,需要的朋友可以參考下2023-10-10
強(qiáng)烈推薦 5 款好用的REST API工具(收藏)
市面上可用的 REST API 工具選項(xiàng)有很多,我們來(lái)看看其中一些開(kāi)發(fā)人員最喜歡的工具。本文通過(guò)圖文實(shí)例代碼相結(jié)合給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2020-12-12

