點(diǎn)贊關(guān)注暴凑,不再迷路,你的支持對我意義重大娶桦!
?? Hi踱蠢,我是丑丑。本文 「Java 路線」| 導(dǎo)讀 —— 他山之石咪辱,可以攻玉 已收錄振劳,這里有 Android 進(jìn)階成長路線筆記 & 博客,歡迎跟著彭丑丑一起成長油狂。(聯(lián)系方式在 GitHub)
前言
- 在 Java 中历恐,編譯產(chǎn)物 .class 是一個(gè)靜態(tài)的存儲(chǔ)結(jié)構(gòu),需要加載到內(nèi)存中的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)专筷,才能為我們所用弱贼。Java 的類加載機(jī)制是很多技術(shù)的基礎(chǔ),同時(shí)也是面試的重點(diǎn)知識(shí)磷蛹,務(wù)必深刻理解吮旅。
- 在這篇文章里,我將分析 Java 類加載機(jī)制的原理味咳,整個(gè)過程分為三個(gè)部分:類查找的委派模型 & 類加載的時(shí)機(jī) & 類加載的流程庇勃。如果能幫上忙,請務(wù)必點(diǎn)贊加關(guān)注槽驶,這真的對我非常重要责嚷。
目錄
1. 類加載的委派模型
1.1 類加載器 = 命名空間
類的唯一性由兩個(gè)因素決定:「類的全限定類名」+「類加載器」。類加載器相當(dāng)于類的命名空間掂铐,要判斷兩個(gè)類是否相同罕拂,除了判斷類名是否相同外揍异,還需要判斷是否由同一個(gè) ClassLoader 加載。
提示: 類的唯一性判斷會(huì)影響:Class#equals聂受、Class#isAssignableFrom()蒿秦、Class#isInstance()烤镐、instanceof 的判斷結(jié)果蛋济。
1.2 類加載的工作機(jī)制
Java 類加載是一種委托機(jī)制(parent delegate),即:除了頂級(jí)啟動(dòng)類加載器(bootstrap classloader)之外炮叶,每個(gè)類加載器都有一個(gè)關(guān)聯(lián)的上級(jí)類加載器(parent 字段)碗旅。當(dāng)一個(gè)類加載器準(zhǔn)備執(zhí)行類加載時(shí),它首先會(huì)委托給上級(jí)加載器去加載镜悉,而上級(jí)加載器可能還會(huì)繼續(xù)向上委托祟辟,遞歸這個(gè)過程。如果上級(jí)構(gòu)造器無法加載侣肄,才會(huì)返回由自己加載旧困。
ClassLoader.java
public abstract class ClassLoader {
上級(jí)類加載器
private final ClassLoader parent;
protected Class<?> loadClass(String name, boolean resolve) {
1、檢查是否加載過
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
2.1 遞歸委派給上級(jí)類加載器
c = parent.loadClass(name, false);
} else {
2.2 委派給頂級(jí)啟動(dòng)類加載器
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
2.3 上級(jí)類加載器無法加載稼锅,拋出異常
}
3. 交給自己加載吼具,findClass() 我后文再說
if (c == null) {
c = findClass(name);
}
}
return c;
}
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
}
提示: 只有 bootstrap classloader 的 parent 字段為空。
1.3 “雙親” 委派是不好的翻譯
在很多資料里會(huì)提到 “雙親委派機(jī)制” 的概念矩距,這其實(shí)是不信達(dá)雅的翻譯了拗盒。 “雙親” 原文是 parent delegate,在 Java 文檔原文的意思:將加載類的任務(wù)委派給上一級(jí)類加載器锥债,而雙親的翻譯卻讓人摸不著頭腦陡蝇。
The Java platform uses a delegation model for loading classes. The basic idea is that every class loader has a "parent" class loader. When loading a class, a class loader first "delegates" the search for the class to its parent class loader before attempting to find the class itself.
1.4 優(yōu)點(diǎn)
- 1、復(fù)用: 使用上級(jí)類加載器加載過的類哮肚,避免重復(fù)加載登夫;
- 2、安全(基礎(chǔ)類型的一致性): 防止加載被篡改的基礎(chǔ)類 .class文件允趟。
1.5 破壞委派模型
- 1恼策、兼容jdk1.2,loadclass不禁止重寫
- 2拼窥、Bootstrap ClassLoader加載用戶類(解決方案:Thread Context ClassLoader)
2. Java 中的類加載器
筆者是 Android 黨戏蔑,這部分內(nèi)容不熟悉,有緣再見鲁纠。如果你對 Android 中的類加載器感興趣总棵,可以看下同系列的這篇文章:「Android 路線」插件化的基本原理
3. 自定義的類加載器
Editting...
4. 類加載的時(shí)機(jī)
Editting...
5. 類加載的流程
5.1 概述
在類加載階段,虛擬機(jī)主要完成三件事情:
- 1改含、通過「類的全限定類名」來加載 「.class 文件的二進(jìn)制字節(jié)流」情龄;
- 2、將「.class 字節(jié)流」轉(zhuǎn)換為「類的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)」(存儲(chǔ)在方法區(qū));
- 3骤视、在 Java 堆中生成一個(gè)「類的 Class 對象」鞍爱,它將作為方法區(qū)類數(shù)據(jù)的訪問入口。
其中第 2 步专酗,將 .class 字節(jié)流轉(zhuǎn)換為類的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)的步驟睹逃,具體分為:
- 1.加載:獲取類的二進(jìn)制字節(jié)流;生成方法區(qū)的運(yùn)行時(shí)存儲(chǔ)結(jié)構(gòu)祷肯;在內(nèi)存中生成 Class 對象 2.驗(yàn)證:確保該 Class 字節(jié)流符合虛擬機(jī)要求 3.準(zhǔn)備:初始化靜態(tài)變量 4.解析:將常量池的符號(hào)引用替換為直接引用 5.初始化:執(zhí)行靜態(tài)塊代碼沉填、類變量賦值
Editting...
6. so 庫加載流程
除了加載類,ClassLoader 還需要負(fù)責(zé)加載 so 庫佑笋,這個(gè)問題在我之前寫過的一篇文章里分析過了:「NDK 路線」| so 庫加載到卸載的全過程翼闹。
7. 總結(jié)
Editting...
參考資料
- 《深入理解Java虛擬機(jī):JVM高級(jí)特性與最佳實(shí)踐(第3版)》(第 7 章) —— 周志明 著
- 《深入理解Android:Java虛擬機(jī)ART》(第 8 章)—— 鄧凡平 著
- 《你知道 Java 類是如何被加載的嗎?》 —— 汪先登 著(阿里巴巴)
創(chuàng)作不易蒋纬,你的「三連」是丑丑最大的動(dòng)力猎荠,我們下次見!