類從被加載到虛擬機(jī)內(nèi)存中開(kāi)始,到卸載出內(nèi)存為止,它的整個(gè)生命周期包括:加載(Loading)、驗(yàn)證(Verification)、準(zhǔn)備(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸載(Unloading)7個(gè)階段。其中準(zhǔn)備、驗(yàn)證、解析3個(gè)部分統(tǒng)稱為連接(Linking)。如圖所示。
加載、驗(yàn)證、準(zhǔn)備、初始化和卸載這5個(gè)階段的順序是確定的,類的加載過(guò)程必須按照這種順序按部就班地開(kāi)始,而解析階段則不一定:它在某些情況下可以在初始化階段之后再開(kāi)始,這是為了支持Java語(yǔ)言的運(yùn)行時(shí)綁定(也稱為動(dòng)態(tài)綁定或晚期綁定)。以下陳述的內(nèi)容都已HotSpot為基準(zhǔn)。
在加載階段(可以參考java.lang.ClassLoader的loadClass()方法),虛擬機(jī)需要完成以下3件事情:
通過(guò)一個(gè)類的全限定名來(lái)獲取定義此類的二進(jìn)制字節(jié)流(并沒(méi)有指明要從一個(gè)Class文件中獲取,可以從其他渠道,譬如:網(wǎng)絡(luò)、動(dòng)態(tài)生成、數(shù)據(jù)庫(kù)等);
將這個(gè)字節(jié)流所代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu);
在內(nèi)存中生成一個(gè)代表這個(gè)類的java.lang.Class對(duì)象,作為方法區(qū)這個(gè)類的各種數(shù)據(jù)的訪問(wèn)入口;
加載階段和連接階段(Linking)的部分內(nèi)容(如一部分字節(jié)碼文件格式驗(yàn)證動(dòng)作)是交叉進(jìn)行的,加載階段尚未完成,連接階段可能已經(jīng)開(kāi)始,但這些夾在加載階段之中進(jìn)行的動(dòng)作,仍然屬于連接階段的內(nèi)容,這兩個(gè)階段的開(kāi)始時(shí)間仍然保持著固定的先后順序。
驗(yàn)證是連接階段的第一步,這一階段的目的是為了確保Class文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機(jī)的要求,并且不會(huì)危害虛擬機(jī)自身的安全。
驗(yàn)證階段大致會(huì)完成4個(gè)階段的檢驗(yàn)動(dòng)作:
文件格式驗(yàn)證:驗(yàn)證字節(jié)流是否符合Class文件格式的規(guī)范;例如:是否以魔術(shù)0xCAFEBABE開(kāi)頭、主次版本號(hào)是否在當(dāng)前虛擬機(jī)的處理范圍之內(nèi)、常量池中的常量是否有不被支持的類型。
元數(shù)據(jù)驗(yàn)證:對(duì)字節(jié)碼描述的信息進(jìn)行語(yǔ)義分析(注意:對(duì)比javac編譯階段的語(yǔ)義分析),以保證其描述的信息符合Java語(yǔ)言規(guī)范的要求;例如:這個(gè)類是否有父類,除了java.lang.Object之外。
字節(jié)碼驗(yàn)證:通過(guò)數(shù)據(jù)流和控制流分析,確定程序語(yǔ)義是合法的、符合邏輯的。
符號(hào)引用驗(yàn)證:確保解析動(dòng)作能正確執(zhí)行。
驗(yàn)證階段是非常重要的,但不是必須的,它對(duì)程序運(yùn)行期沒(méi)有影響,如果所引用的類經(jīng)過(guò)反復(fù)驗(yàn)證,那么可以考慮采用-Xverifynone參數(shù)來(lái)關(guān)閉大部分的類驗(yàn)證措施,以縮短虛擬機(jī)類加載的時(shí)間。
準(zhǔn)備階段是正式為類變量分配內(nèi)存并設(shè)置類變量初始值的階段,這些變量所使用的內(nèi)存都將在方法區(qū)中進(jìn)行分配。這時(shí)候進(jìn)行內(nèi)存分配的僅包括類變量(被static修飾的變量),而不包括實(shí)例變量,實(shí)例變量將會(huì)在對(duì)象實(shí)例化時(shí)隨著對(duì)象一起分配在堆中。其次,這里所說(shuō)的初始值“通常情況”下是數(shù)據(jù)類型的零值,假設(shè)一個(gè)類變量的定義為:
1
publicstaticintvalue=123;
那變量value在準(zhǔn)備階段過(guò)后的初始值為0而不是123.因?yàn)檫@時(shí)候尚未開(kāi)始執(zhí)行任何java方法,而把value賦值為123的putstatic指令是程序被編譯后,存放于類構(gòu)造器()方法之中,所以把value賦值為123的動(dòng)作將在初始化階段才會(huì)執(zhí)行。
至于“特殊情況”是指:public static final int value=123,即當(dāng)類字段的字段屬性是ConstantValue時(shí),會(huì)在準(zhǔn)備階段初始化為指定的值,所以標(biāo)注為final之后,value的值在準(zhǔn)備階段初始化為123而非0.
解析階段是虛擬機(jī)將常量池內(nèi)的符號(hào)引用替換為直接引用的過(guò)程。解析動(dòng)作主要針對(duì)類或接口、字段、類方法、接口方法、方法類型、方法句柄和調(diào)用點(diǎn)限定符7類符號(hào)引用進(jìn)行。
類初始化階段是類加載過(guò)程的最后一步,到了初始化階段,才真正開(kāi)始執(zhí)行類中定義的java程序代碼。在準(zhǔn)備極端,變量已經(jīng)付過(guò)一次系統(tǒng)要求的初始值,而在初始化階段,則根據(jù)程序猿通過(guò)程序制定的主管計(jì)劃去初始化類變量和其他資源,或者說(shuō):初始化階段是執(zhí)行類構(gòu)造器()方法的過(guò)程.
()方法是由編譯器自動(dòng)收集類中的所有類變量的賦值動(dòng)作和靜態(tài)語(yǔ)句塊static{}中的語(yǔ)句合并產(chǎn)生的,編譯器收集的順序是由語(yǔ)句在源文件中出現(xiàn)的順序所決定的,靜態(tài)語(yǔ)句塊只能訪問(wèn)到定義在靜態(tài)語(yǔ)句塊之前的變量,定義在它之后的變量,在前面的靜態(tài)語(yǔ)句塊可以賦值,但是不能訪問(wèn)
原文鏈接 ?http://www.importnew.com/18548.html