基本原理
所有類都由類裝載器載入,載入內存中的類對應一個
java.lang.Class
實例。
已被加載的類由該類的類加載器實例與該類的全路徑名的組合標識。設有
packagename.A Class
,分別被類加載器
CL1
和
CL2
加載,則系統中有兩個不同的
java.lang.Class
實例:
<CL1, packagename.A>
和
<CL2, packagename.A>
。
存在一個
Bootstrap Loader
(以下簡稱為
BL
),由
C++
寫成,負責在虛擬機啟動后一次
性加載
Java
基礎類庫中的所有類。其他的類裝載器由
Java
寫成,都是
java.lang.ClassLoader
的子類。
除
BL
之外的所有類裝載器都有一個
parent
屬性,指向其父裝載器。查閱
java.lang.ClassLoader
的源碼,不難發現類裝載器的委托裝載方式。
?
??
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
來加載,相當于
BL
是其父裝載器)。如果父裝載器也無法裝載,才真正調用自己的
findClass()
方法來裝載。
?????? Java
基礎類在
Java
虛擬機啟動后由
BL
一次性載入。構成
Java
應用程序的其它類在程序運行過程中由不同類裝載器按需通過
loadClass()
方法裝載。
Java
程序啟動過程中的類裝載器
當執行“
java XXX.class
”時,
java.exe
首先找到
JRE
(
Java Runtime Environment
),接著找到位于
JRE
之中的
jvm.dll
,最后載入
jvm.dll
并啟動虛擬機。
虛擬機一啟動,先做一些初始化動作,如獲取系統參數等,然后產生
BL
。
BL
加載
Java
基礎類,這些類都存放在
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
然后創建
sun.misc.Launcher$ExtClassLoader
(
ExtClassLoader
是定義于
sun.misc.Launcher
之內的內部類,繼承自
java.lang.URLClassLoader
)的實例(以下簡稱
EL
)和
sun.misc.Launcher$AppClassLoader
(
AppClassLoader
是定義于
sun.misc.Launcher
之內的內部類,繼承自
URLClassLoader
)的實例(以下簡稱
AL
),并將
EL
的
parent
屬性設置為
null
,
AL
的
parent
屬性設置為
EL
。
?????? EL
在程序運行過程中按需加載保存在
JRE
的“
\lib\ext
”目錄下的類。該目錄可由
System.getProperty(“java.ext.dirs”)
讀出,如
C:\Program Files\Java\jre1.5.0_09\lib\ext
|
?????? AL
在程序運行過程中按需加載的類搜索路徑則是從系統參數
java.class.path
取出的字符串。
java.class.path
是由我們在執行
java.exe
時,利用
-cp
或
-classpath
或
CLASSPATH
環境變量所決定。我們應用程序用到的非
JRE
提供類的搜索路徑一般都配置在
java.class.path
中。
什么時候裝載類,由什么類裝載器裝載
1.?
Java
基礎類由
BL
在虛擬機啟動時一次性載入。
2.?
包含
main()
的入口類由
AL
的
loadClass()
方法載入。
3.?
由
new
關鍵字創建一個類的實例。該類由運行時刻包含該
new
語句的類實例的類裝載器(
ClassLoader.getCallerClassLoader()
)的
loadClass()
方法載入。
4.?
調用
Class.forName()
方法。完整的
forName()
函數版本有一個
ClassLoader
參數,用于指定用什么類裝載器來裝載指定類。
???
public
static
Class<?> forName(String name,
boolean
initialize,
?????????????
?? ClassLoader loader)
throws
ClassNotFoundException
|
??????
對于
public static Class<?> forName(String className)
版本,是由運行時刻包含該語句的類實例的類裝載器(
ClassLoader.getCallerClassLoader()
)的
loadClass()
方法載入。
5.?
調用某個
ClassLoader
實例的
loadClass()
方法。通過該
ClassLoader
實例的
loadClass()
方法載入。應用程序可以通過繼承
ClassLoader
實現自己的類裝載器。
6
.裝載一個類時,首先要裝載該類的基類及其接口。