4

我最近发表了一篇在运行时更新 Java 代码的帖子,经过几个小时摆弄不同的示例代码和阅读教程后,我遇到了以下问题:

通过使用 ClassLoader,我能够在运行时使用http://www.exampledepot.com/egs/java.lang/reloadclass.html上的代码将本地变量从 Class 更改MyVar1为 Class ,但我无法替换该类与另一个版本的.MyVar2MyVar2MyVar2

两者都MyVar1实现MyVar2了一个接口VarInterface。主类使用 type 保存变量的实例VarInterface

我已经阅读了其他几个声称是正确的实现,但我无法让它工作。谁能看到我在这里做错了什么?

主类循环:

    while(true){  
        i++;  
        Thread.sleep(1000);  
        ui.ping();  
        if(i > 3)  
            replaceVar();  
    }

替换变量:

ClassLoader parentClassLoader = MyClassLoader.class.getClassLoader();
    MyClassLoader classLoader = new MyClassLoader(parentClassLoader);
    Class newClass = classLoader.loadClass("MyVar2");
    ui = (VarInterface)newClass.newInstance();

MyClassLoader.loadClass:

public Class<?> loadClass(String what){
    // Get the directory (URL) of the reloadable class
    URL[] urls = null;
    try {
        // Convert the file object to a URL
        File dir = new File(System.getProperty("user.dir")
                +File.separator+"dir"+File.separator);
        URL url = dir.toURL();
        urls = new URL[]{url};
    } catch (MalformedURLException e) {
    }

    // Create a new class loader with the directory
    ClassLoader cl = new URLClassLoader(urls);

    // Load in the class
    Class cls = null;
    try {
        cls = cl.loadClass("MyVar2");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

    return cls;
}

前 3 次迭代MyVar1.ping()被调用,之后MyVar2.ping()被调用 ad infinitum,即使我替换了MyVar2.classMyVar2.java文件。

4

2 回答 2

1

我猜你正在使用两个类加载器。一,系统类加载器,其中包含大量代码。您的自定义类加载器使用系统类加载器作为其父级。您正在尝试让自定义类加载器替换系统类加载器中的类。事实上,自定义类加载器将优先委托给父类,而不是加载自己的类。

您需要做的是确保系统类加载器不加载该类的实现。创建一个加载类的实现并委托给系统类加载器的类加载器。要更改实现,请创建类加载器的另一个实例。

(使用java.net.URLClassLoader.newInstance创建自己的类加载器实现可能更容易。)

于 2010-06-21T00:29:14.310 回答
1

我设法解决了这个问题。我忘记将文件保留在类路径之外,这使得 ClassLoader 仅在它属于实现相同接口的不同类而不是当我用不同版本替换该类时才读取新实例。

所以基本上:通过从项目中删除文件并在外部编辑它们来解决问题。

于 2010-06-21T10:40:29.230 回答