1 開門見山看一道面試題:
答案有點(diǎn)意外吧 我們分析下:
2 類從被加載到虛擬機(jī)內(nèi)存開始障本,直到卸載出內(nèi)存為止锡搜,它的整個生命周期包括了:加載员凝,驗(yàn)證署驻,準(zhǔn)備,解析 初始化 健霹,使用 旺上,卸載。其中驗(yàn)證糖埋,準(zhǔn)備和解析三個部分統(tǒng)稱為鏈接宣吱。
3 何時開始類的初始化
什么情況下需要開始類加載過程的第一個階段"加載"。以下幾種情況瞳别,如果類未初始化會對類進(jìn)行初始化征候。
創(chuàng)建類的實(shí)例
訪問類的靜態(tài)變量
訪問類的靜態(tài)方法
反射如(Class.forName("com.exaple.aaa.Test"))
當(dāng)初始化一個類時,發(fā)現(xiàn)其父類還未初始化祟敛,則先進(jìn)行父類的初始化疤坝。
4 類的加載過程
加載階段是類加載過程的第一個階段,在此階段馆铁,虛擬機(jī)需要完成以下三件事情:
1 通過一個類的全限定名來獲取定義此類的二進(jìn)制字節(jié)流卒煞。
2 將這個字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時數(shù)據(jù)結(jié)構(gòu)。
3 在java堆中生成一個代表這個類的java.lang.Class對象叼架,作為方法區(qū)這些數(shù)據(jù)的訪問入口。
5 驗(yàn)證階段
驗(yàn)證階段是鏈接階段的第一步衣撬,這一階段的目的是為了確保Class文件的字節(jié)流中包含的虛擬機(jī)符合當(dāng)前虛擬機(jī)的要求乖订,并且不會危害虛擬機(jī)自身的安全。
包括:文件格式驗(yàn)證具练,元數(shù)據(jù)驗(yàn)證乍构,字節(jié)碼驗(yàn)證,符號引用驗(yàn)證扛点。
6 準(zhǔn)備階段
是為類的靜態(tài)變量分配內(nèi)存并將其初始化為默認(rèn)值哥遮,這些內(nèi)存都將在方法區(qū)中進(jìn)行分配,準(zhǔn)備階段不分配類中的實(shí)例變量的內(nèi)存陵究,實(shí)例變量將在對象實(shí)例化時隨對象一起分配在java堆中眠饮。
public static final int value=123;
在準(zhǔn)備階段value初始化值為0,在初始化階段才會變成123铜邮。
7 解析階段
是虛擬機(jī)將常量池內(nèi)的符號引用替換成直接引用的過程仪召。
8 初始化
類初始化是類加載的最后一步寨蹋,才開始執(zhí)行類中定義的JAVA程序代碼。
初始化階段是執(zhí)行類構(gòu)造器<clinit>()方法的過程扔茅,方法是由編譯器自動收集類中的所有變量的賦值動作和靜態(tài)語句塊中的語句合并產(chǎn)生的已旧。
我們看上面代碼進(jìn)行分析:
1?SingleTon singleTon = SingleTon.getInstance();調(diào)用了類的靜態(tài)方法,觸發(fā)了類的初始化
2 類加載的時候在準(zhǔn)備過程中為類的靜態(tài)變量分配內(nèi)存并初始化默認(rèn)值
singleTon=null ,count1=0,count2=0
3 類初始化召娜,為類的靜態(tài)變量賦值和執(zhí)行靜態(tài)代碼塊运褪,singleTon賦值為new SingleTon().調(diào)用類的構(gòu)造方法。
4 執(zhí)行完new SingleTon()后count1=0? ? count2=1
5 繼續(xù)為count1 , count2賦值玖瘸,此時count1沒有賦值 count2賦值為0所以結(jié)果如開篇截圖秸讹。
附錄:
對象在class文件加載完畢,以及為格成員方法區(qū)開辟好內(nèi)存空間之后店读,就開始初始化操作:
1 基類靜態(tài)代碼塊嗦枢,基類靜態(tài)成員字段(并列優(yōu)先級,按代碼中出現(xiàn)先后順序) 只有第一次加載類時執(zhí)行
2 派生類靜態(tài)代碼塊 屯断,派生類靜態(tài)成員字段(并列優(yōu)先級文虏,按代碼中出現(xiàn)先后順序) 只有第一次加載類時執(zhí)行
3 基類普通代碼塊,基類普通成員字段(并列優(yōu)先級殖演,按代碼中出現(xiàn)先后順序)
4 基類的構(gòu)造函數(shù)
3 派生類普通代碼塊氧秘,派生類普通成員字段(并列優(yōu)先級,按代碼中出現(xiàn)先后順序)
4 派生類的構(gòu)造函數(shù)