目錄
1.類加載介紹
2.具體步驟
2.1加載
2.2驗證
2.3準備
2.4解析
2.5初始化
3.加載過程中的策略-雙親委派模型
1.類加載介紹
類加載,指的是Java進程在運行的時候,把.class文件從硬盤讀取到內存,并進行一系列校驗解析的過程.
.class文件=>類對象.硬盤=>內村
類加載的過程在Java官方文檔中有說明
類加載大致可以分為五個步驟:即 加載.驗證 準備 解析 初始化這五個步驟.
下面我們分別來介紹這五個步驟干了一些什么
2.具體步驟
2.1加載
把硬盤上的.class文件找到并且打開文件,讀取到文件內容.(具體就是二進制的數據)
2.2驗證
此過程要確保讀到的文件內容是合法的.class文件格式,即字節碼文件格式
具體在Java虛擬機規范中有具體的說明.
類似于一個結構體的東西?
其中,u4表示四個字節的無符號證書,u2是連個字節的無符號整數.這里的描述方式類似于C語言中的結構體.contant_pool_count是主版本.下面的是次版本/ jvm執行.class文件的時候就會驗證版本是否符合要求,一般高版本可以兼容低版本,反之則不行.magic也叫做magic number 是魔幻數字,廣泛應用于二進制文件中,用來標識當前二進制文件的格式是哪種類型
2.3準備
這一步是給類對象申請內存空間.此時申請的內存空間是已經初始化的.里面的默認值為全0.在這個階段中,類對象的靜態成員變量的值也相對于是0了.
2.4解析
主要是對類的字符串常量進行處理 我們觀察一下代碼:
class Test{
?private String s = "hello";
}
上述代碼中,s變量相對于保存了"hello"這個字符串常量的地址.但是文件中并沒有地址這個概念,那么該如何保存呢?雖然沒有地址,但是有一個類似于地址的偏移量的這一概念
/
此除文件填充給s "hello"的偏移量就可以叫做"符號引用"
接下來,我們把.class文件加載到內存中,就會把"hello"這個字符串加載到內存中.此時它就有地址了,接下來,就可以把s里的值替換成當前"hello"的真實地址了.
2.5初始化
針對對象完成后續的初始化,就是把各個部分的屬性進行賦值填充.=>還要執行靜態代碼的邏輯,黑客拿會觸發父類的加載.
而加載過程中也有很多的貓膩.這就涉及到加載環節的一個模型,即雙親委派模型
3.加載過程中的策略-雙親委派模型
該策略描述了如何查找.class文件的策略/
jvm中進行類加載的操作,有一個專門的模塊,稱為類加載器(ClassLoader)
JVM的類加載器默認有三個.(也可以自定義 ) 這三個分別是?
BootstrapClassLoader? -負責查找標準庫的目錄
ExtensionClassLoader - 負責查找擴展庫的目錄 (不同于Java語法規范中的標準庫內容,這都是實現jvm的廠商額外擴充的功能,不同的廠商擴展的不一樣,這塊內容很少會用到了)
ApplicationLoader -負責查找當前項目和第三方庫的目錄
上述的三個類加載器存在父子關系,類似于二叉樹,有一個指針 (引用)指向parent,指向自己的父類加載器.
雙親委派模型的工作過程
1.從ApplicationClassLoader為入口 開始工作
2?從ApplicationClassLoader不會立即工作而是把搜索任務較給自己的父親ExtensionClassLoader
3ExtensionClassLoader也不會立即尋找,而是交給BootstrapClassLoader?
4BootstrapClassLoader 也不會立即找,也會找自己的父親
5.BootstrapClassLoader 發現自己沒有父親,才會開始搜索目錄,即標準庫的內容 尋找符合要求的.class文件,如果找到了就開始打開文件.讀文件.如果沒找到就交給自己的孩子.嘗試加載
6.ExtensionClassLoader收到父親的任務后,自己搜尋.找到了進入后續流程.找不到就繼續到孩子這一類加載器中嘗試加載
7?ApplicationClassLoader開始搜索,如果找到了.就繼續后面的,如果沒找到就搜索自己的孩子,一般來說ApplicationClassLoader它已經沒有孩子了,這時候還是找不到,就會拋出一個ClassNotFountExption異常.
按照上述的設定,如果代碼中自己定義了一個和標準庫一樣名字的類,最終程序的執行效果,自己定義的不會被加載,而是會加載標準庫中的類.
可以避免自己寫的類名字和標準庫重名了,導致標準庫的類功能失效.