1茧妒、類的加載
1. 裝載類的第一階段
2. 獲取類的二進制流
2.1 從本地系統(tǒng)中直接加載
2.2 通過網(wǎng)絡下載.class文件
2.3 從zip,jar等歸檔文件中加載.class文件
2.4 從專有數(shù)據(jù)庫中提取.class文件
2.5 將Java源文件動態(tài)編譯為.class文件
3. 轉(zhuǎn)為方法區(qū)的數(shù)據(jù)結(jié)構(gòu)
4. 在java堆中生成java.long.Class對象
2记某、鏈接
- 2.1 驗證
1. 文件格式驗證
1.1 是否以0xCAFEBABE開頭
1.2 版本號是否合理
1.3 常量池中的常量是否有不被支持的類型
2. 元數(shù)據(jù)驗證【簡單的說就是java中基本的語法和語義是否符合規(guī)范】
2.1 是否有父類
2.2 繼承了final類
2.3 非抽象類是否實現(xiàn)了所有的抽象方法
3. 字節(jié)碼驗證【很復雜 我也不是很懂 ╮( ̄▽ ̄)╭ 】
3.1 運行檢查
3.2 棧數(shù)據(jù)類型和操作碼數(shù)據(jù)參數(shù)吻合
3.3 跳轉(zhuǎn)指令到合理的位置
4. 符號引用驗證
4.1 常量池中描述類是否存在
4.2 訪問的方法或者字段是否具有足夠的權(quán)限【public、protected、private】
- 2.2 準備
1. 分配內(nèi)存,并為類設置初始值(方法區(qū)中)
2. public static int v =1;
3. 在準備階段中焕议,v會被值為0;
4. 在初始化的<clinit>中才會被值為1弧关;
5. 對于static final類型盅安,在準備階段就就會被賦上正確的值
6. public static final int v =1;
- 2.3 解析
1. 將符號引用替換直接引用;
2. 什么是符號引用
2.1 符號引用就是字符串 假設我有一個User類默認超類就是java.lang.Object 那么它在class的常量池中有個字符串 字符串就是"java.lang.Object"
2.2 直接引用就是指針和地址偏移量
3. 初始化
1. 執(zhí)行類構(gòu)造器<clinit>
1.1 變量 賦值語句
1.2 static{}語句會被執(zhí)行
2. 子類的<clinit>調(diào)用前保證父類的<clinit>被調(diào)用
3. <clinit>是線程安全的世囊;
4.ClassLoader
- 4.1 什么是類裝載器ClassLoader
1. ClassLoader是一個抽象類
2. ClassLoader的實例將讀入Java字節(jié)碼將類裝載到JVM中
3. ClassLoader可以定制别瞭,滿足不同字節(jié)碼流獲取方式
4. ClassLoader負責類裝載過程中的加載階段
- 4.2 ClassLoader的種類
1. BootStrap ClassLoader (啟動ClassLoader)
2. Extension ClassLoader (擴展ClassLoader)
3. App ClassLoader (應用ClassLoader/系統(tǒng)ClassLoader)
4. Custom ClassLoader(自定義ClassLoader)
5.雙親委托機制
-
5.1 雙親委托機制圖解
5.2 雙親委托機制源碼解析
1. 檢查類是否已被加載過,調(diào)用 findClassLoaded() 查看當前類加載器是否存在 class 的緩存
2. 若類未被加載過株憾,遞歸委托父類加載器調(diào)用 loadClass() 加載類蝙寨,若無,則 findBootstrapClassOrNull() 完成類加載
3. 若以上步驟都不能完成類加載,則調(diào)用 findClass() 嘗試當前類加載器完成加載籽慢,若加載成功則緩存
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// 檢查類是否已被加載過
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
//遞歸委托父類加載器加載類
c = parent.loadClass(name, false);
} else {
//無父類加載器浸遗,則調(diào)用啟動類加載器加載
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
long t1 = System.nanoTime();
//遞歸委托后仍然無法完成類加載,則使用當前類加載器加載
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
- 5.3 雙親委托機制意義
1. Class的唯一性【同一個加載器加載同一份class文件】
2. 保證Java程序安全穩(wěn)定運行