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