、概述
首先先來看幾個(gè)問題
jvm是如何加載這些Class文件的?
jvm加載一個(gè)Class文件需要哪些步驟?
Class文件中的信息進(jìn)入到虛擬機(jī)后會(huì)發(fā)生什么變化?
接下來看看jvm加載class文件的概述:
jvm把描述類的數(shù)據(jù)從class文件加載到內(nèi)存,并對(duì)數(shù)據(jù)進(jìn)行校驗(yàn),轉(zhuǎn)換解析和初始化,最終形成可以被虛擬機(jī)直接使用的Java類型,這就是虛擬機(jī)的類加載機(jī)制。這句話差不多已經(jīng)回答上面三個(gè)問題的大部分了。
與那些在編譯是需要進(jìn)行連接工作的語言不同,在Java語言里面,類型的加載和連接過程都是在程序運(yùn)行期間完成的,這樣會(huì)在類加載是稍微增加一些性能開銷,但是卻能為Java應(yīng)用程序提供高度的靈活性,Java中可以動(dòng)態(tài)的擴(kuò)展的語言特性就是依賴運(yùn)行期動(dòng)態(tài)加載和動(dòng)態(tài)連接這個(gè)特點(diǎn)實(shí)現(xiàn)的。比如編寫一個(gè)使用接口的應(yīng)用程序,可以等到運(yùn)行時(shí)在指定其實(shí)際的實(shí)現(xiàn)。這種組裝應(yīng)用程序的方式廣泛應(yīng)用于Java程序之中。
二、要點(diǎn)
類從被加載到j(luò)vm內(nèi)存中開始,到卸載出內(nèi)存為止,它的生命周期包括了一下步驟:加載(Loading)、驗(yàn)證(Verification)、準(zhǔn)備(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Useing)和卸載(Unloading)七個(gè)階段。其中的驗(yàn)證、準(zhǔn)備和解析三個(gè)部分統(tǒng)稱為鏈接(Linking),這七個(gè)階段的發(fā)生順序如下圖,注意是發(fā)生的順序,不是執(zhí)行完成的先后順序。
1、加載
加載階段是“類加載”過程的一個(gè)階段,虛擬機(jī)需要做以下三件事:
通過一個(gè)類的全限定名來獲取定義此類的二進(jìn)制字節(jié)流。
將這個(gè)字節(jié)流所代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)。
在Java堆中生成一個(gè)代表這個(gè)類的java.lang.Class對(duì)象,作為方法區(qū)這些數(shù)據(jù)的入口。
加載階段完成后,虛擬機(jī)外部的二進(jìn)制字節(jié)流就按照虛擬機(jī)所需的格式存儲(chǔ)在方法區(qū)之中,方法區(qū)中的數(shù)據(jù)存儲(chǔ)格式有虛擬機(jī)實(shí)現(xiàn)自定義,虛擬機(jī)規(guī)范未規(guī)定此區(qū)域的具體數(shù)據(jù)結(jié)構(gòu)。然后再Java堆中實(shí)例化一個(gè)java.lang.Class類的對(duì)象,這個(gè)對(duì)象作為程序訪問方法區(qū)中的這些類型數(shù)據(jù)的外部接口。加載階段與連接階段的部分內(nèi)容是交替進(jìn)行的,加載階段尚未完成,連接階段可能已經(jīng)開始,但這些夾在加載階段之中進(jìn)行的動(dòng)作,仍然屬于連接階段的內(nèi)容,這兩個(gè)階段的開始時(shí)間仍然保持著固定的先后順序。
2、驗(yàn)證
驗(yàn)證階段虛擬機(jī)做了下面這些事情
1、文件格式驗(yàn)證
第一階段是要驗(yàn)證字節(jié)流是否符合Class文件格式的規(guī)范,并且能被當(dāng)前版本的虛擬機(jī)處理。會(huì)驗(yàn)證一下這些內(nèi)容。
主、次版本號(hào)是否在當(dāng)前虛擬機(jī)處理范圍之內(nèi)。
常量池的常量中是否有不被支持的常量類型。
指向常量的各種索引值中是否有指向不存在的常量或不符合類型的常量。
CONSTANT_Utf8_info型的常量中是否有不符合UTF8編碼的數(shù)據(jù)。
Class文件中各部分及文件本身是否有被刪除的或附加的其他信息
2、元數(shù)