首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

《深入理解 Java 虛擬機》讀書筆記(二):虛擬機類加載機制全景解析

     編輯:Java 綜合教學

《深入理解 Java 虛擬機》讀書筆記(二):虛擬機類加載機制全景解析

一、類加載過程總覽

執行時機: 編譯期 → 運行期(JVM 啟動、程序運行),類加載發生在程序運行期間。

階段劃分: 加載 → 連接(驗證、準備、解析) → 初始化 → 使用 → 卸載

執行順序: 大體按上述階段依次執行,但相互交叉:
加載 → 驗證(文件格式) → 繼續加載 → 解析 → 驗證(元數據、字節碼) → 準備 → 初始化

參與角色: Class 文件、Java 虛擬機、類加載器
HotSpot 的 Bootstrap ClassLoader (啟動類加載器) 位於虛擬機內部 (C++ 實現),其他類加載器外置於 JVM (Java 實現)


二、各階段深度解析

1. 加載階段

普通類/接口、數組類(組件類型為基本類型如 int[][]):

  • 獲取:類加載器按「全限定名」獲取 Class 文件 (平台無關的二進制字節流)
  • 轉化:字節碼按規範轉化為方法區存儲格式
  • 創建:方法區生成代表該類的 java.lang.Class 對象
  • 觸發:加載時觸發父類、關聯引用類加載
    class A extends B → Class<B>
    private Class<Person> clazz → Class<Person>
    Class c = Person.class → Class<Person>

2. 類加載器體系與雙親委派模型

1. 類加載器層級:
   Bootstrap Loader (啟動類加載器)
     → 加載 JAVA_HOME/lib 下字節碼 (rt.jar 等)
     → 路徑由 sun.boot.class.path 指定
   Extended Loader (擴展類加載器 ExtClassLoader)
     → 加載 JAVA_HOME/lib/ext 下字節碼
     → 路徑由 java.ext.dirs 指定
   AppClass Loader (系統/應用程序類加載器 AppClassLoader)
     → 加載 classpath 下字節碼
     → 路徑由 java.class.path 指定
   自定義類加載器
     → 繼承 ClassLoader 重寫 findClass() (JDK1.2+ 推薦)

2. 雙親委派模型關係圖:
   [圖片: https://ss0.bdstatic.com/.../timg?image&quality=100...]
   關系:父持有子引用 (has-a)
   分工:收到加載請求先委派父加載器,父找不到才由子加載
   好處:Java 類隨加載器具備優先級層次,保護核心類庫不被篡改

3. Class 對象身份判定

同一 Class 文件被同一類加載器加載,才判定為相等。意義:

  1. 相等 → 僅生成一個 Class 對象;不相等 → 生成多個。
  2. 只有同一 Class 對象,equals()、isAssignableFrom()、instanceof、isInstance() 結果才一致。

4. 數組類加載策略

  • 組件類型為基本類型 (如 int[][]):直接生成 Class 對象,標記「已加載」。
  • 組件類型為引用類型 (如 Person[][]):遞歸加載組件類型,每次去掉一個維度。

5. 連接階段

  • 驗證:文件格式、元數據、字節碼驗證
  • 準備:為類變量分配內存並初始化默認值
    關鍵區別:
    static int i = 20;       // 編譯期產生 ConstantValue 屬性,但不存 20
                             // 準備階段:常規初始化 → i = 0
    
    final static int i = 20; // 編譯期產生 ConstantValue 並存 20
                             // 準備階段:從 ConstantValue 取值 → i = 20
  • 解析:將運行時常量池符號引用替換為直接引用 (指向內存目標的句柄),又稱「靜態綁定/靜態連接」

6. 初始化階段 (動態綁定/動態連接)

觸發時機 — 主動引用:

  • new 實例化
  • 反射調用
  • 初始化子類觸發父類初始化
  • 執行包含 main 方法的主類
  • 調用靜態方法/訪問靜態字段

執行順序示例 (筆試高頻):

public class Father {
    private static int i = 20;
    static { System.out.println("Father static before: " + i); i = 50; System.out.println("Father static after: " + i); }
    public Father() { System.out.println("Father constructor: " + i); }
}
public class Son extends Father {
    private static int i = 20;
    static { System.out.println("Son static before: " + i); i = 50; System.out.println("Son static after: " + i); }
    public Son() { System.out.println("Son constructor: " + i); }
}
public class Main {
    public static void main(String[] args) { new Son(); }
}
/* 輸出:
Father static before: 20
Father static after: 50
Son static before: 20
Son static after: 50
Father constructor: 50
Son constructor: 50
*/

順序:父類 <clinit> → 子類 <clinit> → 父類 <init> → 子類 <init>

被動引用: 會觸發類加載但不會初始化 (如訪問父類靜態字段、定義對象數組、調用 Class.forName 且 initialize=false 等)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved