Java中類的加載器及其加載過程
Java中類的加載器及其加載過程
概述
字節(jié)碼文件在類加載器子系統(tǒng)中要進行加載、鏈接、初始化等處理,我們這里詳細來談其中過程
類加載器子系統(tǒng)負責(zé)從文件系統(tǒng)或網(wǎng)絡(luò)中加載Class文件,且ClassLoader只負責(zé)class文件的加載,至于其能否運行,則交由ExecutionEngine來判斷。
加載的類信息存放于一塊稱為方法區(qū)的內(nèi)存空間。除了類的信息以外,方法區(qū)中還會存放運行時常量池信息,可能還包括字符串字面量和數(shù)字常量(這部分常量信息是Class文件中常量池部分的內(nèi)存映射)
??class文件最終加載到JVM中,根據(jù)這個文件可以實例化出n個一模一樣的實例,加載到JVM的class文件則被稱為DNA元數(shù)據(jù)模板,放在方法區(qū)。而在這整個文件到元數(shù)據(jù)模板的過程中,類裝載器就起到了一個轉(zhuǎn)換器的作用
轉(zhuǎn)換和執(zhí)行過程:
首先需要裝載目標類,再進行鏈接,然后對其進行初始化,最終調(diào)用對應(yīng)類中的方法
所以,類的加載過程如下??
過程一:Loading
這個過程也稱為加載,但和類的加載不同,這個加載只是其中的一個環(huán)節(jié),切莫搞混,我們這里用Loading來代替,以防混淆
Loading過程:
- 通過一個類的全限定名獲取定義此類的二進制字節(jié)流
- 將這個字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法去的運行時數(shù)據(jù)結(jié)構(gòu)
- 再內(nèi)存中生成一個代表這個類的java.lang.Class對象,作為方法區(qū)這個類的各種數(shù)據(jù)的訪問入口
加載.class文件的幾種方式:
- 從本地系統(tǒng)中直接加載
- 通過系統(tǒng)網(wǎng)絡(luò)獲取,典型場景:Web Applet
- 從zip壓縮包中獲取,成為日后jar、war格式的基礎(chǔ)
- 運行時計算生成,使用最多的是:動態(tài)代理技術(shù)
- 由其他文件生成,典型場景:JSP應(yīng)用
- 從專有數(shù)據(jù)庫中提取.class文件,比較少見
- 從加密文件中獲取
過程二:Linking
鏈接階段包括驗證(Verify)、準備(Prepare)、解析(Resolve)
Verify
目的在于確保Class文件的字節(jié)流中包含信息符合當(dāng)前虛擬機要求,保證被加載類的正確性,不會威脅虛擬機自身的安全。
驗證有四種形式:
- 文件格式驗證
- 元數(shù)據(jù)驗證
- 字節(jié)碼驗證
- 符號引用驗證
e.g.:
class字節(jié)碼文件中以CAFEBABE開頭,以供識別
Prepare
該階段為類的變量分配內(nèi)存表并且設(shè)置該變量的默認初始值,即零值。
不包含用final修飾的static,因為final在編譯的時候就會分配了,準備階段會進行顯式初始化
同樣也不會為實例變量分配初始化,類變量會分配在方法區(qū)中,但實例變量會隨著對象一起分配到j(luò)ava堆中
Resolve
該階段將常量池內(nèi)的符號引用轉(zhuǎn)換為直接引用的過程
事實上,解析操作往往會伴隨著JVM在執(zhí)行完初始化之后再執(zhí)行
符號引用就是一組符號來描述所引用的目標,符號引用的字面量形式明確定義在《java虛擬機規(guī)范》的class文件格式中。直接引用就是直接指向目標的指針、相對偏移量或一個間接定位到目標的句柄
解析動作主要針對類或接口、字段、類方法、接口方法、方法類型等。對應(yīng)常量池中的CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info等
過程三:Initialization
該過程是執(zhí)行類構(gòu)造器方法()的過程
此方法不需定義,是javac虛擬機自動收集類中的所有類變量的賦值動作和靜態(tài)代碼塊中的語句合并而來,所以如果沒有這兩項操作,就不存在這個過程。
這里會出現(xiàn)一個神奇的現(xiàn)象:
static{ number = 20; } private static int number = 10;
這樣也可以執(zhí)行,而執(zhí)行結(jié)果為10,究其原因,number在prepare中早已初始化,并賦值為0,而來到Initialization階段中才會開始進行賦值,首先執(zhí)行static塊中的number = 20,后再執(zhí)行number = 10的賦值操作,最后結(jié)果為10。
*但在static中不能對其進行引用/調(diào)用,比如打印操作,會報錯:Illegal forward reference*
構(gòu)造器方法中指令按語句在源文件中出現(xiàn)的順序執(zhí)行
()不同于類的構(gòu)造器(關(guān)聯(lián):構(gòu)造器是虛擬機視角下的())
若該類具有父類,JVM會保證子類的()執(zhí)行前,父類的()已經(jīng)執(zhí)行完畢
虛擬機必須保證一個類的()方法在多線程下被同步加鎖
到此這篇關(guān)于Java中類的加載器及其加載過程的文章就介紹到這了,更多相關(guān)Java類加載器及過程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
kafka 啟動報錯 missingTopicsFatal is true的解決
這篇文章主要介紹了kafka 啟動報錯 missingTopicsFatal is true的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07springboot使用hibernate validator校驗方式
hibernate validator提供了一套比較完善、便捷的驗證實現(xiàn)方式。下面小編給大家介紹下springboot使用hibernate validator校驗方式,感興趣的朋友一起看看吧2018-01-01JavaWeb中使用JavaMail實現(xiàn)發(fā)送郵件功能實例詳解
這篇文章主要介紹了JavaWeb中使用JavaMail實現(xiàn)發(fā)送郵件功能的實例代碼,非常不錯具有參考借鑒價值,感興趣的朋友一起看看吧2016-05-05maven多個plugin相同phase的執(zhí)行順序
這篇文章主要介紹了maven多個plugin相同phase的執(zhí)行順序,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-12-12詳解如何在SpringBoot項目中使用統(tǒng)一返回結(jié)果
在一個完整的項目中,如果每一個控制器的方法都返回不同的結(jié)果,那么對項目的維護和擴展都會很麻煩。因此,本文為大家準備了SpringBoot項目中使用統(tǒng)一返回結(jié)果的方法,需要的可以參考一下2022-10-10