繁体   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