使用ClassLoader加载内部类

时间:2014-05-16 05:37:04

标签: java inner-classes urlclassloader

我正在编写一个程序,允许用户将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是我的程序中用来管理这些&#34的控制台命令。 ;插件&#34;类。就像我上面说的,这个代码适用于外部类,问题是当我尝试加载内部类时。我的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);
}

我的程序工作方式,它从用户收到一个String,然后调用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或成功加载的类时,它返回外部和内部类。但是,当我运行程序并通过&#34; testinput&#34;对于条件和执行方法,这是我的输出。

  

测试...线程中的异常&#34; Execute_Thread_Test_Handler&#34;   java.lang.NoClassDefFoundError:   plugins / event_handlers / Test_Handler $ TestInner at   plugins.event_handlers.Test_Handler.execute(Test_Handler.java:11)​​at   events.ThreadEventExecutor.run(ThreadEventExecutor.java:20)引起:   抛出java.lang.ClassNotFoundException:   plugins.event_handlers.Test_Handler $ TestInner at   java.net.URLClassLoader $ 1.run(未知来源)at   java.net.URLClassLoader $ 1.run(未知来源)at   java.security.AccessController.doPrivileged(Native Method)at   java.net.URLClassLoader.findClass(未知来源)at   java.lang.ClassLoader.loadClass(未知来源)at   java.lang.ClassLoader.loadClass(未知来源)......另外2个

我想要打印的是

  

...测试   内在的作品!   内课已经过测试   它有效吗?

最后我的问题是,我如何使上述代码有效?我不想让我的用户编写他们自己的类加载器,这样就加载了一个内部/单独的类(因为并非我的所有用户在编码​​时都必然是惊人的)所以我需要能够引用内部类类型而不需要代码爆炸。

1 个答案:

答案 0 :(得分:0)

自从我提出要求以来已经很长时间了,但我在代码和类加载器javadocs之间来回浏览,我只是愚蠢。

在我的loadClassByName2中,我调用classLoader.close();如果新加载的类将要加载更多的类,则不应该这样做。

根据javadocs,每个类类型都会跟踪加载它的类加载器。如果该类类型需要引用一个卸载的类,它会调用其类加载器来查找并加载它。当我在加载单个类之后立即关闭类加载器时,我做了它,因此类加载器无法找到/加载任何其他类(包括本地/内部类)。