(JavaSE高級)五、Java 的類加載器

1. Java 的類加載器的種類都有哪些缎患?

1慕的、根類加載器(Bootstrap) --C++寫的 ,看不到源碼
2挤渔、擴(kuò)展類加載器(Extension) --加載位置 :jre\lib\ext 中
3肮街、系統(tǒng)(應(yīng)用)類加載器(System\App) --加載位置 :classpath 中
4、自定義加載器(必須繼承 ClassLoader)

2. 類什么時(shí)候被初始化判导?

1)創(chuàng)建類的實(shí)例嫉父,也就是 new 一個(gè)對象
2)訪問某個(gè)類或接口的靜態(tài)變量,或者對該靜態(tài)變量賦值
3)調(diào)用類的靜態(tài)方法
4)反射(Class.forName("com.lyj.load"))
5)初始化一個(gè)類的子類(會(huì)首先初始化子類的父類)
6)JVM 啟動(dòng)時(shí)標(biāo)明的啟動(dòng)類眼刃,即文件名和類名相同的那個(gè)類
只有這 6 中情況才會(huì)導(dǎo)致類的類的初始化绕辖。
類的初始化步驟:
1)如果這個(gè)類還沒有被加載和鏈接,那先進(jìn)行加載和鏈接
2)假如這個(gè)類存在直接父類擂红,并且這個(gè)類還沒有被初始化(注意:在一個(gè)類加載器中仪际,類只能初始化一
次),那就初始化直接的父類(不適用于接口)

  1. 假如類中存在初始化語句(如 static 變量和 static 塊)昵骤,那就依次執(zhí)行這些初始化語句树碱。

3. Java 類加載體系之 ClassLoader 雙親委托機(jī)制

java 是一種類型安全的語言,它有四類稱為安全沙箱機(jī)制的安全機(jī)制來保證語言的安全性涉茧,這四類安全
沙箱分別是:
1) 類加載體系
2) .class 文件檢驗(yàn)器
3) 內(nèi)置于 Java 虛擬機(jī)(及語言)的安全特性
4) 安全管理器及 Java API
主要講解類的加載體系:
java 程序中的 .java 文件編譯完會(huì)生成 .class 文件赴恨,而 .class 文件就是通過被稱為類加載器的 ClassLoader
加載的,而 ClassLoder 在加載過程中會(huì)使用“雙親委派機(jī)制”來加載 .class 文件伴栓,先上圖:


image.png
  • BootStrapClassLoader: 啟 動(dòng) 類 加 載 器 伦连, 該 ClassLoader 是 jvm 在 啟 動(dòng) 時(shí) 創(chuàng) 建 的 菜枷, 用 于 加載$JAVA_HOME$/jre/lib下面的類庫(或者通過參數(shù)-Xbootclasspath 指定)珊豹。由于啟動(dòng)類加載器涉及到虛擬機(jī)本地實(shí)現(xiàn)細(xì)節(jié),開發(fā)者無法直接獲取到啟動(dòng)類加載器的引用御铃,所以不能直接通過引用進(jìn)行操作饺窿。
  • ExtClassLoader:擴(kuò)展類加載器歧焦,該ClassLoader是在sun.misc.Launcher里作為一個(gè)內(nèi)部類ExtClassLoader
    定義的(即sun.misc.Launcher$ExtClassLoader),ExtClassLoader 會(huì)加載$JAVA_HOME/jre/lib/ext下的類庫(或者通過參數(shù)-Djava.ext.dirs 指定)。
  • AppClassLoader:應(yīng)用程序類加載器绢馍,該 ClassLoader 同樣是在 sun.misc.Launcher 里作為一個(gè)內(nèi)部類
    AppClassLoader 定義的(即sun.misc.Launcher$AppClassLoader)向瓷,AppClassLoader 會(huì)加載 java 環(huán)境變量CLASSPATH 所 指 定 的 路 徑 下 的 類 庫 , 而 CLASSPATH 所 指 定 的 路 徑 可 以 通 過System.getProperty("java.class.path")獲冉⒂俊猖任;當(dāng)然,該變量也可以覆蓋瓷耙,可以使用參數(shù)-cp朱躺,例如:java -cp 路徑 (可以指定要執(zhí)行的 class 目錄)。
  • CustomClassLoader:自定義類加載器搁痛,該 ClassLoader 是指我們自定義的 ClassLoader长搀,比如 tomcat 的StandardClassLoader 屬于這一類;當(dāng)然鸡典,大部分情況下使用 AppClassLoader 就足夠了源请。

前面談到了ClassLoader的幾類加載器,而ClassLoader是用雙親委派機(jī)制來加載class文件的轿钠。ClassLoader
的雙親委派機(jī)制是這樣的(這里先忽略掉自定義類加載器 CustomClassLoader):
1)當(dāng) AppClassLoader 加載一個(gè) class 時(shí)巢钓,它首先不會(huì)自己去嘗試加載這個(gè)類,而是把類加載請求委派給父
類加載器 ExtClassLoader 去完成疗垛。
2)當(dāng) ExtClassLoader 加載一個(gè) class 時(shí)症汹,它首先也不會(huì)自己去嘗試加載這個(gè)類,而是把類加載請求委派給
BootStrapClassLoader 去完成贷腕。
3)如果 BootStrapClassLoader 加載失敱痴颉(例如在$JAVA_HOME$/jre/lib里未查找到該 class),會(huì)使用
ExtClassLoader 來嘗試加載泽裳;
4)若 ExtClassLoader 也加載失敗瞒斩,則會(huì)使用 AppClassLoader 來加載,如果 AppClassLoader 也加載失敗涮总,則會(huì)報(bào)出異常 ClassNotFoundException胸囱。
下面貼下 ClassLoader 的 loadClass(String name, boolean resolve)的源碼:

1.protected synchronized Class<?> loadClass(String name, boolean resolve)
2. throws ClassNotFoundException {
3. // 首先找緩存是否有 class
4. Class c = findLoadedClass(name);
5. if (c == null) {
6. //沒有判斷有沒有父類
7. try {
8. if (parent != null) {
9. //有的話,用父類遞歸獲取 class
10. c = parent.loadClass(name, false);
11. } else {
12. //沒有父類瀑梗。通過這個(gè)方法來加載
13. c = findBootstrapClassOrNull(name);
14. }
15. } catch (ClassNotFoundException e) {
16. // ClassNotFoundException thrown if class not found
17. // from the non-null parent class loader
18. }
19. if (c == null) {
20. // 如果還是沒有找到烹笔,調(diào)用 findClass(name)去找這個(gè)類
21. c = findClass(name);
22. }
23. }
24. if (resolve) {
25. resolveClass(c);
26. }
27. return c;
28. }

代碼很明朗:首先找緩存(findLoadedClass),沒有的話就判斷有沒有 parent抛丽,有的話就用 parent 來遞歸
的 loadClass谤职,然而 ExtClassLoader 并沒有設(shè)置 parent,則會(huì)通過 findBootstrapClassOrNull 來加載 class亿鲜,而
findBootstrapClassOrNull 則會(huì)通過 JNI 方法”private native Class findBootstrapClass(String name)“來使
用 BootStrapClassLoader 來加載 class允蜈。然后如果 parent 未找到 class,則會(huì)調(diào)用 findClass 來加載 class,findClass 是一個(gè) protected 的空方法饶套,可以覆蓋它以便自定義 class 加載過程漩蟆。

另 外 , 雖 然 ClassLoader 加 載 類 是 使 用 loadClass 方 法 凤跑, 但 是 鼓 勵(lì) 用 ClassLoader 的 子 類 重寫
findClass(String)爆安,而不是重寫 loadClass,這樣就不會(huì)覆蓋了類加載默認(rèn)的雙親委派機(jī)制仔引。

雙親委派托機(jī)制為什么安全?
舉個(gè)例子,ClassLoader 加載的 class 文件來源很多褐奥,比如編譯器編譯生成的 class咖耘、或者網(wǎng)絡(luò)下載的字節(jié)碼。而一些來源的 class 文件是不可靠的撬码,比如我可以自定義一個(gè) java.lang.Integer 類來覆蓋 jdk 中默認(rèn)的 Integer類儿倒,例如下面這樣:

1. package java.lang;
2. public class Integer {
3. public Integer(int value) {
4. System.exit(0);
5. }
6. }

初始化這個(gè) Integer 的構(gòu)造器是會(huì)退出 JVM,破壞應(yīng)用程序的正常進(jìn)行呜笑,如果使用雙親委派機(jī)制的話該Integer 類永遠(yuǎn)不會(huì)被調(diào)用夫否,因?yàn)槲?BootStrapClassLoader 加載后會(huì)加載 JDK 中的 Integer 類而不會(huì)加載自定義的這個(gè),可以看下下面這測試個(gè)用例:

1.public static void main(String... args) {
2. Integer i = new Integer(1);
3. System.err.println(i);
4. }

執(zhí)行時(shí) JVM 并未在 new Integer(1)時(shí)退出叫胁,說明未使用自定義的 Integer凰慈,于是就保證了安全性。

4. 描述一下 JVM 加載 class

JVM 中類的裝載是由類加載器(ClassLoader)和它的子類來實(shí)現(xiàn)的驼鹅,Java 中的類加載器是一個(gè)重要的 Java 運(yùn)行時(shí)系統(tǒng)組件微谓,它負(fù)責(zé)在運(yùn)行時(shí)查找和裝入類文件中的類。由于 Java 的跨平臺(tái)性输钩,經(jīng)過編譯的 Java 源程序并不是一個(gè)可執(zhí)行程序豺型,而是一個(gè)或多個(gè)類文件。當(dāng) Java 程序需要使用某個(gè)類時(shí),JVM 會(huì)確保這個(gè)類已經(jīng)被加載买乃、連接(驗(yàn)證姻氨、準(zhǔn)備和解析)和初始化。

類的加載是指把類的.class文件中的數(shù)據(jù)讀入到內(nèi)存中剪验,通常是創(chuàng)建一個(gè)字節(jié)數(shù)組讀入.class 文件肴焊,然后產(chǎn)生與所加載類對應(yīng)的 Class 對象。加載完成后碉咆,Class 對象還不完整抖韩,所以此時(shí)的類還不可用。當(dāng)類被加載后就進(jìn)入連接階段疫铜,這一階段包括驗(yàn)證茂浮、準(zhǔn)備(為靜態(tài)變量分配內(nèi)存并設(shè)置默認(rèn)的初始值)和解析(將符號引用替換為直接引用)三個(gè)步驟。最后 JVM 對類進(jìn)行初始化,包括:

  • 如果類存在直接的父類并且這個(gè)類還沒有被初始化席揽,那么就先初始化父類顽馋;
  • 如果類中存在初始化語句,就依次執(zhí)行這些初始化語句幌羞。

類的加載是由類加載器完成的寸谜,類加載器包括:根加載器(BootStrap)、擴(kuò)展加載器(Extension)属桦、系統(tǒng)加載器(System)和用戶自定義類加載器(java.lang.ClassLoader的子類)熊痴。從 Java 2(JDK 1.2)開始,類加載過程采取了父親委托機(jī)制(PDM)聂宾。PDM 更好的保證了 Java 平臺(tái)的安全性果善,在該機(jī)制中,JVM 自帶的 Bootstrap 是根加載器系谐,其他的加載器都有且僅有一個(gè)父類加載器巾陕。類的加載首先請求父類加載器加載,父類加載器無能為力時(shí)才由其子類加載器自行加載纪他。JVM 不會(huì)向 Java 程序提供對 Bootstrap 的引用鄙煤。
下面是關(guān)于幾個(gè)類加載器的說明:

  • Bootstrap:一般用本地代碼實(shí)現(xiàn),負(fù)責(zé)加載 JVM 基礎(chǔ)核心類庫(rt.jar)茶袒;
  • Extension:從 java.ext.dirs 系統(tǒng)屬性所指定的目錄中加載類庫梯刚,它的父加載器是 Bootstrap;
  • System:又叫應(yīng)用類加載器弹谁,其父類是 Extension乾巧。它是應(yīng)用最廣泛的類加載器。它從環(huán)境變量 classpath
    或者系統(tǒng)屬性 java.class.path 所指定的目錄中記載類预愤,是用戶自定義加載器的默認(rèn)父加載器沟于。

5. 獲得一個(gè)類對象有哪些方式?

類型.class植康,例如:String.class
對象.getClass()旷太,例如:”hello”.getClass()
Class.forName(),例如:Class.forName(“java.lang.String”)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末销睁,一起剝皮案震驚了整個(gè)濱河市供璧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌冻记,老刑警劉巖睡毒,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異冗栗,居然都是意外死亡演顾,警方通過查閱死者的電腦和手機(jī)供搀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來钠至,“玉大人葛虐,你說我怎么就攤上這事∶蘧” “怎么了屿脐?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長宪卿。 經(jīng)常有香客問我的诵,道長,這世上最難降的妖魔是什么佑钾? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任奢驯,我火速辦了婚禮,結(jié)果婚禮上次绘,老公的妹妹穿的比我還像新娘。我一直安慰自己撒遣,他們只是感情好邮偎,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著义黎,像睡著了一般禾进。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上廉涕,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天泻云,我揣著相機(jī)與錄音,去河邊找鬼狐蜕。 笑死宠纯,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的层释。 我是一名探鬼主播婆瓜,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼贡羔!你這毒婦竟也來了廉白?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤乖寒,失蹤者是張志新(化名)和其女友劉穎猴蹂,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體楣嘁,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡磅轻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年珍逸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瓢省。...
    茶點(diǎn)故事閱讀 40,001評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡弄息,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出勤婚,到底是詐尸還是另有隱情摹量,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布馒胆,位于F島的核電站缨称,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏祝迂。R本人自食惡果不足惜睦尽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望型雳。 院中可真熱鬧当凡,春花似錦、人聲如沸纠俭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽冤荆。三九已至朴则,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間钓简,已是汗流浹背乌妒。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留外邓,地道東北人撤蚊。 一個(gè)月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像坐榆,于是被迫代替她去往敵國和親拴魄。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容