王森《Java 深度歷險》以 JVM 內部機制為主線,深入剖析類別載入、JNI、執行緒、記憶體模型等核心主題。本文整理前三章關鍵知識點,作為深入理解 Java 運行時期的基石。
執行 java MyClass 時,啟動器依序搜尋 JRE:
jre 目錄。jre 子目錄。HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment 記錄的安裝路徑。實務啟示:環境變數 JAVA_HOME 與 PATH 設定須與實際安裝一致,避免多版本 JRE 共存導致「類別版本不符」或「找不到 JVM」錯誤。
Class.forName("className"):預設使用呼叫者類別的載入器,會執行靜態初始化 (<clinit>)。ClassLoader.loadClass("className"):指定載入器,**不執行靜態初始化**,需手動 clazz.newInstance() 觸發。| 載入器 | 實現語言 | 搜尋路徑來源 | 修改方式 | 職責 |
|---|---|---|---|---|
| Bootstrap ClassLoader | C++ (JVM 內建) | sun.boot.class.path (預設 jre/lib/rt.jar 等) | java -Xbootclasspath/p:path (前置) / /a: (附加) | 核心類別庫 (java.*, javax.*) |
| Extension ClassLoader | Java (sun.misc.Launcher$ExtClassLoader) | java.ext.dirs (預設 jre/lib/ext) | java -Djava.ext.dirs=path | 擴充套件 (JCE, XML Parser 等) |
| Application ClassLoader | Java (sun.misc.Launcher$AppClassLoader) | java.class.path (環境變數 CLASSPATH 或 -cp) | java -cp path / Class-Path Manifest | 應用程式類別 |
AppClassLoader.loadClass()
│ 委派給父載入器
▼
ExtClassLoader.loadClass()
│ 委派給父載入器
▼
Bootstrap Loader.findClass() → 找到則返回
│ 找不到
▼
ExtClassLoader.findClass() → 找到則返回
│ 找不到
▼
AppClassLoader.findClass() → 找到則返回 / 拋出 ClassNotFoundException
核心原則:請求向上委派,載入向下尋找。確保核心類別不被應用程式竄改 (如無法自定 java.lang.String)。
DriverManager)、JNDI、SPI 機制 (ServiceLoader) 需要**逆向載入**:啟動器載入的類別 (如 java.sql.DriverManager) 需載入應用程式提供的實作類別。Thread.currentThread().getContextClassLoader() 通常指向 AppClassLoader,打破雙親委派限制。native 方法:public native void createWordDoc(String path);javac 編譯 → javah -jni ClassName 產生 .h 標頭檔。jni.h,使用 JNIEnv* 操作 Java 物件)。.dll, Linux/macOS .so。System.loadLibrary("mylib") 載入,或 System.load("/full/path/libmylib.so")。| 函式 | 用途 |
|---|---|
FindClass | 載入 Java 類別 |
GetMethodID / GetFieldID | 取得方法/欄位 ID |
CallVoidMethod / CallIntMethod | 呼叫 Java 實例方法 |
NewStringUTF / GetStringUTFChars | Java String ↔ C char* 轉換 |
NewObjectArray / GetObjectArrayElement | 陣列操作 |
ThrowNew | 拋出 Java 例外 |
RegisterNatives | 靜態註冊 (效能優於動態查找) |
NewGlobalRef/DeleteGlobalRef)。PushLocalFrame/PopLocalFrame 管理引用框架。