載入外部 .class 檔案

要載入一個類,我們首先需要定義它。該類由 ClassLoader 定義。只有一個問題,Oracle 沒有使用此功能編寫 ClassLoader 的程式碼。要定義類,我們需要訪問名為 defineClass() 的方法,這是 ClassLoader 的私有方法。

要訪問它,我們要做的是建立一個新類 ByteClassLoader,並將其擴充套件到 ClassLoader。現在我們已經將類擴充套件到了 ClassLoader,我們可以訪問 ClassLoader 的私有方法。為了使 defineClass() 可用,我們將建立一個新方法,它將像私有 defineClass() 方法的映象一樣。要呼叫私有方法,我們需要類名 name,類位元組,classBytes,第一個位元組的偏移量,這將是 0 因為 classBytes‘資料從 classBytes[0] 開始,而最後一個位元組的偏移量將是 classBytes.lenght,因為它代表資料的大小,這將是最後的偏移量。

public class ByteClassLoader extends ClassLoader {

    public Class<?> defineClass(String name, byte[] classBytes) {
        return defineClass(name, classBytes, 0, classBytes.length);
    }

}

現在,我們有一個公共的 defineClass() 方法。可以通過將類的名稱和類位元組作為引數傳遞來呼叫它。

假設我們在包裝中提到了名為 MyClass 的類……

要呼叫該方法,我們需要類位元組,因此我們使用 Paths.get() 方法建立一個 Path 物件來表示我們的類路徑,並將二進位制類的路徑作為引數傳遞。現在,我們可以使用 Files.readAllBytes(path) 獲取類位元組。所以我們建立了一個 ByteClassLoader 例項並使用我們建立的方法 defineClass()。我們已經有了類位元組但是為了呼叫我們的方法,我們還需要類名,它由包名稱(點)給出了類規範名稱,在本例中為 stackoverflow.MyClass

Path path = Paths.get("MyClass.class");

ByteClassLoader loader = new ByteClassLoader();
loader.defineClass("stackoverflow.MyClass", Files.readAllBytes(path);

注意defineClass() 方法返回 Class<?> 物件。如果需要,你可以儲存它。

要載入類,我們只需呼叫 loadClass() 並傳遞類名。這個方法可以丟擲一個 ClassNotFoundException 所以我們需要使用 try cath 塊

try{
    loader.loadClass("stackoverflow.MyClass");
} catch(ClassNotFoundException e){
    e.printStackTrace();
}