基本原理
所有類都由類裝載器載入,載入內(nèi)存中的類對應(yīng)一個(gè) java.lang.Class 實(shí)例。
已被加載的類由該類的類加載器實(shí)例與該類的全路徑名的組合標(biāo)識。設(shè)有 packagename.A Class ,分別被類加載器 CL1 和 CL2 加載,則系統(tǒng)中有兩個(gè)不同的 java.lang.Class 實(shí)例: <CL1, packagename.A> 和 <CL2, packagename.A> 。
存在一個(gè) Bootstrap Loader (以下簡稱為 BL ),由 C++ 寫成,負(fù)責(zé)在虛擬機(jī)啟動后一次
性加載 Java 基礎(chǔ)類庫中的所有類。其他的類裝載器由 Java 寫成,都是 java.lang.ClassLoader 的子類。
除 BL 之外的所有類裝載器都有一個(gè) parent 屬性,指向其父裝載器。查閱 java.lang.ClassLoader 的源碼,不難發(fā)現(xiàn)類裝載器的委托裝載方式。
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
{
// First, check if the class has already been loaded
Class c = findLoadedClass(name);
if (c == null ) {
try {
if ( parent != null ) {
c = parent .loadClass(name, false );
} else {
c = findBootstrapClass0(name);
}
} catch (ClassNotFoundException e) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
|
對于給定的類名,首先檢查自己是否已加載過該類。如果沒有,則首先通過父裝載器加載(如果 parent==null ,則直接通過 BL 來加載,相當(dāng)于 BL 是其父裝載器)。如果父裝載器也無法裝載,才真正調(diào)用自己的 findClass() 方法來裝載。
Java 基礎(chǔ)類在 Java 虛擬機(jī)啟動后由 BL 一次性載入。構(gòu)成 Java 應(yīng)用程序的其它類在程序運(yùn)行過程中由不同類裝載器按需通過 loadClass() 方法裝載。
Java 程序啟動過程中的類裝載器
當(dāng)執(zhí)行“ java XXX.class ”時(shí), java.exe 首先找到 JRE ( Java Runtime Environment ),接著找到位于 JRE 之中的 jvm.dll ,最后載入 jvm.dll 并啟動虛擬機(jī)。
虛擬機(jī)一啟動,先做一些初始化動作,如獲取系統(tǒng)參數(shù)等,然后產(chǎn)生 BL 。 BL 加載 Java 基礎(chǔ)類,這些類都存放在 JRE 中的 lib 目錄下,可由 System.getProperty(“sun.boot.class.path”) 列出,如:
C:\Program Files\Java\jre1.5.0_09\lib\rt.jar;
C:\Program Files\Java\jre1.5.0_09\lib\i18n.jar;
C:\Program Files\Java\jre1.5.0_09\lib\sunrsasign.jar;
C:\Program Files\Java\jre1.5.0_09\lib\jsse.jar;
C:\Program Files\Java\jre1.5.0_09\lib\jce.jar;
C:\Program Files\Java\jre1.5.0_09\lib\charsets.jar;
C:\Program Files\Java\jre1.5.0_09\classes
|
BL 然后創(chuàng)建 sun.misc.Launcher$ExtClassLoader ( ExtClassLoader 是定義于 sun.misc.Launcher 之內(nèi)的內(nèi)部類,繼承自 java.lang.URLClassLoader )的實(shí)例(以下簡稱 EL )和 sun.misc.Launcher$AppClassLoader ( AppClassLoader 是定義于 sun.misc.Launcher 之內(nèi)的內(nèi)部類,繼承自 URLClassLoader )的實(shí)例(以下簡稱 AL ),并將 EL 的 parent 屬性設(shè)置為 null , AL 的 parent 屬性設(shè)置為 EL 。
EL 在程序運(yùn)行過程中按需加載保存在 JRE 的“ \lib\ext ”目錄下的類。該目錄可由 System.getProperty(“java.ext.dirs”) 讀出,如
C:\Program Files\Java\jre1.5.0_09\lib\ext
|
AL 在程序運(yùn)行過程中按需加載的類搜索路徑則是從系統(tǒng)參數(shù) java.class.path 取出的字符串。 java.class.path 是由我們在執(zhí)行 java.exe 時(shí),利用 -cp 或 -classpath 或 CLASSPATH 環(huán)境變量所決定。我們應(yīng)用程序用到的非 JRE 提供類的搜索路徑一般都配置在 java.class.path 中。
什么時(shí)候裝載類,由什么類裝載器裝載
1. Java 基礎(chǔ)類由 BL 在虛擬機(jī)啟動時(shí)一次性載入。
2. 包含 main() 的入口類由 AL 的 loadClass() 方法載入。
3. 由 new 關(guān)鍵字創(chuàng)建一個(gè)類的實(shí)例。該類由運(yùn)行時(shí)刻包含該 new 語句的類實(shí)例的類裝載器( ClassLoader.getCallerClassLoader() )的 loadClass() 方法載入。
4. 調(diào)用 Class.forName() 方法。完整的 forName() 函數(shù)版本有一個(gè) ClassLoader 參數(shù),用于指定用什么類裝載器來裝載指定類。
public static Class<?> forName(String name, boolean initialize,
ClassLoader loader) throws ClassNotFoundException
|
對于 public static Class<?> forName(String className) 版本,是由運(yùn)行時(shí)刻包含該語句的類實(shí)例的類裝載器( ClassLoader.getCallerClassLoader() )的 loadClass() 方法載入。
5. 調(diào)用某個(gè) ClassLoader 實(shí)例的 loadClass() 方法。通過該 ClassLoader 實(shí)例的 loadClass() 方法載入。應(yīng)用程序可以通過繼承 ClassLoader 實(shí)現(xiàn)自己的類裝載器。
6 .裝載一個(gè)類時(shí),首先要裝載該類的基類及其接口。