簡體   English   中英

使用ClassLoader加載內部類

[英]Loading Inner Classes using a ClassLoader

我正在編寫一個程序,允許用戶在文本區域中鍵入Java代碼,然后對其進行編譯並將其作為一種“插件”加載到程序中。 我目前能夠編譯.java文件並加載外部類,但是我無法正確地加載/實例化由用戶編寫的內部類。 目前,這是我用來加載外部類的方法,此代碼有效,並且我能夠輕松使用外部類而不會產生任何復雜性。 (如果您發現拼寫錯誤,我做了一些編輯以提高可讀性)

private ArrayList<String> execute(ArrayList<String> fileNames) {
    ArrayList<String> successStories = new ArrayList();
    ArrayList<Class<?>> eventHandlers = new ArrayList();
    // Load all classes first...
    for (int i = 0; i < fileNames.size(); i++) {
        Class<?> clazz = loadClassByName2(fileNames.get(i));
        if (EventHandler.class.isAssignableFrom(clazz)) {
            eventHandlers.add(clazz);
            successStories.add(fileNames.get(i));
        } else if (InterfaceInnerClass.class.isAssignableFrom(clazz)) {
            successStories.add(fileNames.get(i));
        } else {
            System.out.println(clazz.getName() + " couldn't be loaded");
        }
    }
    // Then instantiate the handlers.
    for (int i = 0; i < eventHandlers.size(); i++) {
        try {
            Object obj = eventHandlers.get(i).newInstance();
            if (obj instanceof EventHandler) {
                EventHandler EH = (EventHandler)obj;
                EH.name = EH.getClass().getSimpleName();
                CmdEvents.addEvent(EH);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    return successStories;
}

public static Class<?> loadClassByName2(String name) {
    try {
        // My program sets up classpath environment variables so "./" is all that is needed as the URL
        URLClassLoader classLoader = new URLClassLoader(
                new URL[] { new File("./").toURI().toURL() });
        // Load the class from the classloader by name....
        Class<?> c = classLoader.loadClass("plugins.event_handlers." + name);
        classLoader.close();
        return c;
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

文件名的原始列表是從GUI發送的,列出了插件目錄中的每個.class文件。 用戶選擇要加載的類,單擊按鈕,然后將這些文件名發送到這些方法。 在此代碼中,EventHandler是一個類,您將在下面看到,InterfaceInnerClass只是用作標記的接口,以確保沒有任何嚴重的問題,而CmdEvents是我程序中用於管理這些“插件”類的控制台命令。 就像我在上面說過的那樣,此代碼對於外部類可以正常工作,問題是當我嘗試加載內部類時。 我的EventHandler抽象類的代碼如下。

public abstract class EventHandler {
    public String name; // Don't mind this being public, I have my reasons for this.

    public abstract void execute(String input);
    public abstract boolean condition(String input);
}

我的程序的工作方式是,它從用戶那里接收字符串,然后調用condition(String),如果返回true,則調用execute(String)。 我編寫了一些測試代碼來嘗試如下所述的加載程序。

package plugins.event_handlers;
public class Test_Handler extends events.EventHandler {

    public void execute(String input) {
        System.out.println("Testing...");

        TestInner inner = new TestInner();
        inner.test();

        System.out.println("Did it work?");
    }
    public boolean condition(String input) {
        return input.contains("testinput");
    }
    public class TestInner implements events.InterfaceInnerClass {
        public TestInner() {
            System.out.println("The inner works!");
        }

        public void test() {
            System.out.println("Inner class has been tested");
        }
    }
}

我運行程序,選擇Test_Handler.class和Test_Handler $ TestInner.class,然后單擊按鈕。 當該方法返回ArrayList或成功加載的類時,它將同時返回外部類和內部類。 但是,當我運行程序並將“ testinput”傳遞給條件並執行方法時,這就是我的輸出。

正在測試...線程“ Execute_Thread_Test_Handler”中的異常java.lang.NoClassDefFoundError:plugins.event_handlers.Test_Handler.execute(Test_Handler.java:11)​​處的plugins / event_handlers / Test_Handler $ TestInner在events.ThreadEventExecutor.run(ThreadEventExecutor.java:20:20) )原因:java.lang.ClassNotFoundException:java.net.URLClassLoader $ 1.run(unknown Source)處的plugins.event_handlers.Test_Handler $ TestInner在java.security.AccessController處java.net.URLClassLoader $ 1.run(Unknown Source)處。 java.net.URLClassLoader.findClass(未知源)的doPrivileged(本地方法)java.lang.ClassLoader.loadClass(未知源)的java.lang.ClassLoader.loadClass(未知源)... 2另外

我要打印的是

測試中...內部工作! 內部班級已經過測試是否有效?

所以最后我的問題是,如何使以上代碼起作用? 我不想讓我的用戶編寫自己的類加載器,而不必加載一個內部/單獨的類(因為並非我的所有用戶都一定會對編碼感到驚奇),所以我需要能夠引用內部類類型而無需代碼炸毀。

自從我問了這已經很長時間了,但是我在代碼和類加載器javadocs之間來回瀏覽,我簡直是愚蠢。

在我的loadClassByName2中,我調用classLoader.close();。 如果新加載的類要加載更多的類,則不應這樣做。

根據javadocs,每種類類型都會跟蹤加載它的類加載器。 如果該類類型曾經需要引用一個已卸載的類,它將調用其類加載器來查找並加載它。 當我在加載單個類后立即關閉類加載器時,我完成了該操作,因此該類加載器無法查找/加載任何其他類(包括本地/內部類)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM