1. 程式人生 > >如何載入Class檔案到JVM

如何載入Class檔案到JVM

如下圖所示,是ClassLoader載入一個class檔案到JVM時需要經過的步驟:
這裡寫圖片描述

第一階段是找到.class檔案並把這個檔案包含的位元組碼載入到記憶體中。
第二階段又可以分為三個步驟,分別是位元組碼驗證、Class類資料結構分析及相應的記憶體分配和最後的符號表的連結。
第三階段是類中靜態屬性和初始化賦值,以及靜態塊的執行。

載入位元組碼到記憶體

其實在抽象類ClassLoader中並沒有定義如何去載入,如何去找到指定類並且把它的位元組碼載入到記憶體需要在子類中去實現,也就是要實現findClass()方法。看下在URLClassLoader中如何實現findeClass的,在URLClassLoader中通過一個URLClassPath類幫助取得要載入的class檔案位元組流,而這個URLClassPath定義了到哪裡去找這個class檔案,如果找到了這個class檔案,再讀取它的byte位元組流,然後通過呼叫defineClass方法來建立類物件。
原始碼如下:

   protected Class<?> findClass(final String name)
        throws ClassNotFoundException
    {
        final Class<?> result;
        try {
            result = AccessController.doPrivileged(
                new PrivilegedExceptionAction<Class<?>>() {
                    public
Class<?> run() throws ClassNotFoundException { String path = name.replace('.', '/').concat(".class"); Resource res = ucp.getResource(path, false); if (res != null) { try { return
defineClass(name, res); } catch (IOException e) { throw new ClassNotFoundException(name, e); } } else { return null; } } }, acc); } catch (java.security.PrivilegedActionException pae) { throw (ClassNotFoundException) pae.getException(); } if (result == null) { throw new ClassNotFoundException(name); } return result; }

我們再來看一下URLClassLoader類的建構函式,我們發現,必須要指定一個URL資料才能夠建立URLClassLoader物件,也就是必須要指定這個ClassLoader預設到哪個目錄下去查詢class檔案。

   public URLClassLoader(URL[] urls) {
        super();
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            security.checkCreateClassLoader();
        }
        ucp = new URLClassPath(urls);
        this.acc = AccessController.getContext();
    }

這個URL陣列也是建立URLClassPath物件的必要條件。從URLClassPath的名字中就可以發現它是通過URL的形式來表示ClassPath路徑的。
在 建立URLClassPath物件時,會根據傳過來的URL資料中的路徑來判斷時檔案還是jar包,根據路徑的不同分別建立FileLoader或者JarLoader,或者使用預設的載入器。當JVM呼叫findeClass時這幾個載入器來將class檔案的位元組碼載入到記憶體中。
如何設定每個ClassLoader的搜尋路徑呢?
下表是BootStrap ClassLoader、ExtClassLoader和AppClassLoader的引數形式

classLoader型別 引數選項 說明
BootStrap ClassLoader -Xbootclasspath: 設定BootStrap ClassLoader的搜尋路徑
ExtClassLoader -Xbootclasspath/a: -Xbootclasspath/p: 把路徑新增到已存在BootStrap ClassLoader搜尋路徑的後面(a)和前面(p)
AppClassLoader -Djava.ext.dirs 設定AppClassLoader的搜尋路徑
AppClassLoader -Djava.class.path= -cp或-classpath 設定AppClassLoader的搜尋路徑

在上面的引數設定中,最常用到的就是設定classpath 的環境變數,因為通常都是讓Java執行指定的程式。如果在通過命令執行一個類時出現NoClassDefFoundError錯誤,那麼很可能是沒有指定classpaht所致,或者指定了classpath但是沒有指明包名。

驗證與解析

  • 位元組碼驗證,類裝入器對於類的位元組碼要做許多檢測,以確保格式正確、行為正確。
  • 類準備,在這個階段準備代表每個類中定義的欄位、方法和實現介面所必需的資料結構。
  • 解析,在這個階段,類裝入器裝入類所引用的其他所有類。可以用許多方式引用類,如超類、介面、欄位、方法簽名、方法中使用的本地變數。

初始化class物件

在類中包含的靜態初始化器都被執行,在這一階段末尾靜態欄位被初始化為預設值。