Java類加載機制,你了解嗎?
1、類的加載
類的加載是指將類的.class文件讀取進內(nèi)存中,并將其放在JVM運行時數(shù)據(jù)區(qū)的方法區(qū)內(nèi),然后在堆中創(chuàng)建一個java.lang.Class對象,用于封裝類在方法區(qū)中的數(shù)據(jù)結(jié)構(gòu),同時作為方法區(qū)數(shù)據(jù)的訪問入口。
2、類的生命周期
類的生命周期指一個class文件從加載到卸載的整個過程

3、類的加載過程
JVM將類的加載分為三個階段:裝載(Load)、鏈接(Link)、初始化(Initialize)
3.1 裝載:查找并加載類的二進制數(shù)據(jù)
在硬盤上查找并通過IO讀入字節(jié)碼文件,使用到類時才會加載,例如調(diào)用類的main()方法,new對象等等,在加載階段會在內(nèi)存中生成一個代表這個類的Java.lang.Class對象,作為方法區(qū)這個類的各種數(shù)據(jù)的訪問入口。
3.2 鏈接:驗證、準(zhǔn)備、解析
驗證
校驗字節(jié)碼文件的正確性、安全性,包括四種驗證:文件格式驗證、元數(shù)據(jù)的驗證、字節(jié)碼驗證、符號引用驗證準(zhǔn)備
為類變量(static修飾的字段變量)分配內(nèi)存并且設(shè)置該類變量的初始值,這里不包含final修飾的static,因為final在編譯的時候就已經(jīng)分配了。也不會為實例變量分配初始化,實例變量會隨著對象分配到堆內(nèi)存中。解析
把常量池中的符號引用轉(zhuǎn)換為直接引用,靜態(tài)鏈接過程
3.3 初始化:初始化靜態(tài)變量,執(zhí)行靜態(tài)代碼塊
3.3.1 類的初始化時機
如果一個類被直接引用,就會觸發(fā)類的初始化。在Java中,直接引用的情況有:
通過new關(guān)鍵字實例化對象、讀取或設(shè)置類的靜態(tài)變量、調(diào)用類的靜態(tài)方法
通過反射執(zhí)行以上三種行為
初始化子類的時候,會觸發(fā)父類的初始化
作為程序的入口直接運行時(main方法)

3.3.2 類初始化步驟
假如這個類還沒有被加載和鏈接,則程序先加載并連接該類(動態(tài)加載:主類在運行過程中如果使用到其他類,會逐步加載這些類 eg:jar包和war包中的類并不是一次性都加載到內(nèi)存中,而是使用時才加載)
假如該類的直接父類還沒有被初始化,則先初始化其直接父類
假如類中有初始化語句,則系統(tǒng)依次執(zhí)行這些初始化語句

4、類加載后方法區(qū)存儲內(nèi)容
類被加載到方法區(qū)中后主要包含運行時常量池、類型信息、字段信息、方法信息、類加載器的引用、對應(yīng)class實例的引用等信息。
類加載器的引用:這個類到類加載器實例的引用
對應(yīng)class實例的引用:類加載器在加載類信息放到方法區(qū)中后,會創(chuàng)建一個對應(yīng)的Class 類型的對象實例放到堆(Heap)中, 作為開發(fā)人員訪問方法區(qū)中類定義的入口和切入點。
5、類加載器
類加載過程主要通過類加載器實現(xiàn),Java中有以下幾種類加載器:
引導(dǎo)類加載器(Bootstrap ClassLoader)
負(fù)責(zé)加載支撐JVM運行的位于JRE的lib目錄下的核心類庫,比如rt.jar\charsets.jar等,由C++實現(xiàn),不是ClassLoader子類,Java程序無法直接引用。拓展類加載器(Extension ClassLoader)
負(fù)責(zé)加載支撐JVM運行的位于JRE的lib目錄下的ext拓展目錄中的類庫應(yīng)用類加載器(App ClassLoader)
負(fù)責(zé)加載ClassPath路徑下的類包,主要加載開發(fā)人員寫的類自定義類加載器(Custom ClassLoader)
負(fù)責(zé)加載用戶自定義路徑下的類包
類加載器之間存在父子層級結(jié)構(gòu):




6、雙親委派機制
6.1 定義
雙親委派機制是指當(dāng)一個類加載器收到一個類加載請求時,該類加載器首先會把請求委派給父類加載器。每個類加載器都是如此,只有在父類加載器在自己的加載路徑下找不到指定類時,子類才會嘗試自己去加載。
6.2 工作過程

當(dāng)應(yīng)用程序類加載器收到一個類加載請求時,他首先不會自己去嘗試加載這個類,而是將這個請求委派給父類加載器Extension ClassLoader去完成。
當(dāng)Extension ClassLoader收到一個類加載請求時,他首先也不會自己去嘗試加載這個類,而是將請求委派給父類加載器Bootstrap ClassLoader去完成。
如果Bootstrap ClassLoader加載失敗(在<JAVA_HOME>\lib中未找到所需類),就會讓Extension ClassLoader嘗試加載。
如果Extension ClassLoader也加載失敗,就會使用Application ClassLoader加載。
如果Application ClassLoader也加載失敗,就會使用自定義加載器去嘗試加載。
如果均加載失敗,就會拋出ClassNotFoundException異常。
6.3 雙親委托機制實現(xiàn)源碼(JDK 1.8)

6.4 雙親委托作用
沙箱安全機制:防止核心類庫被篡改,自己寫的java.lang.String不會被加載。
避免類的重復(fù)加載:當(dāng)父加載器已經(jīng)加載過該類時,子加載器就沒必要重新加載一次,保證被加載類的唯一性。


7、自定義類加載器

8、如何打破雙親委派機制
核心:繼承ClassLoader,重寫類加載方法,實現(xiàn)加載邏輯,不委托給雙親加載

