旅游網(wǎng)站開發(fā)項目策劃書中國四大軟件外包公司
JVM:雙親委派機制
- 1. 例子
- 2. 類加載器總結
- 3. 類加載過程
- 4. 雙親委派模型的執(zhí)行流程:
- 5. 雙親委派模型的好處
1. 例子
Java運行時環(huán)境有一個java.lang
包,里面有一個ClassLoader
類
我們自定義一個String
類在java.lang
包下,下面的main方法報錯。原因是: 根據(jù)雙親委派機制,會向上找先是找到了應用程序加載器(appClassLoader) ,然后向上找擴展類加載器(ExtClassLoader),最后找根類加載器(Boot Strap Loader),發(fā)現(xiàn)有String執(zhí)行根加載器的也就是rt.jar
包中的。 其實就是上級的加載器有的就執(zhí)行上級的
2. 類加載器總結
JVM 中內(nèi)置了三個重要的 ClassLoader:
BootstrapClassLoader(啟動類加載器)
:最頂層的加載類,由 C++實現(xiàn),通常表示為 null,并且沒有父級,主要用來加載 JDK 內(nèi)部的核心類庫( %JAVA_HOME%/lib目錄下的 rt.jar 、resources.jar 、charsets.jar等 jar 包和類)以及被 -Xbootclasspath參數(shù)指定的路徑下的所有類。ExtensionClassLoader(擴展類加載器)
:主要負責加載 %JRE_HOME%/lib/ext 目錄下的 jar 包和類以及被 java.ext.dirs 系統(tǒng)變量所指定的路徑下的所有類。AppClassLoader(應用程序類加載器)
:面向我們用戶的加載器,負責加載當前應用 classpath 下的所有 jar 包和類。
簡單來說,類加載器的主要作用就是加載 Java 類的字節(jié)碼( .class 文件)到 JVM 中(在內(nèi)存中生成一個代表該類的 Class 對象)。 字節(jié)碼可以是 Java 源程序(.java文件)經(jīng)過 javac 編譯得來,也可以是通過工具動態(tài)生成或者通過網(wǎng)絡下載得來。
3. 類加載過程
- 類加載過程:加載->連接->初始化。
- 連接過程又可分為三步:驗證->準備->解析。
加載是類加載過程的第一步,主要完成下面 3 件事情:
- 通過全類名獲取定義此類的二進制字節(jié)流
- 將字節(jié)流所代表的靜態(tài)存儲結構轉換為方法區(qū)的運行時數(shù)據(jù)結構
- 在內(nèi)存中生成一個代表該類的 Class 對象,作為方法區(qū)這些數(shù)據(jù)的訪問入口
4. 雙親委派模型的執(zhí)行流程:
- 在類加載的時候,系統(tǒng)會首先判斷當前類是否被加載過。已經(jīng)被加載的類會直接返回,否則才會嘗試加載(每個父類加載器都會走一遍這個流程)。
- 類加載器在進行類加載的時候,它首先不會自己去嘗試加載這個類,而是把這個請求委派給父類加載器去完成(調(diào)用父加載器 loadClass()方法來加載類)。這樣的話,所有的請求最終都會傳送到頂層的啟動類加載器 BootstrapClassLoader 中。
- 只有當父加載器反饋自己無法完成這個加載請求(它的搜索范圍中沒有找到所需的類)時,子加載器才會嘗試自己去加載(調(diào)用自己的 findClass() 方法來加載類)。
5. 雙親委派模型的好處
雙親委派模型保證了 Java 程序的穩(wěn)定運行,可以避免類的重復加載(JVM 區(qū)分不同類的方式不僅僅根據(jù)類名,相同的類文件被不同的類加載器加載產(chǎn)生的是兩個不同的類),也保證了 Java 的核心 API 不被篡改。
如果沒有使用雙親委派模型,而是每個類加載器加載自己的話就會出現(xiàn)一些問題,比如我們編寫一個稱為 java.lang.Object
類的話,那么程序運行的時候,系統(tǒng)就會出現(xiàn)兩個不同的 Object 類。雙親委派模型可以保證加載的是 JRE 里的那個 Object 類,而不是你寫的 Object 類。這是因為 AppClassLoader
在加載你的 Object 類時,會委托給 ExtClassLoader 去加載,而ExtClassLoader
又會委托給 BootstrapClassLoader,BootstrapClassLoader
發(fā)現(xiàn)自己已經(jīng)加載過了 Object 類,會直接返回,不會去加載你寫的 Object 類。