使用类加载器重新加载代码时遇到的Java问题

使用类加载器重新加载代码时遇到的Java问题,java,class,classloader,reloading,Java,Class,Classloader,Reloading,我最近发表了一篇文章,在花了几个小时摆弄不同的示例代码和阅读教程之后,我遇到了以下问题: 通过使用类加载器,我能够在运行时使用处的代码将本地变量从类MyVar1更改为类MyVar2,但我无法用另一个版本的MyVar2替换该类MyVar2 MyVar1和MyVar2都实现了一个接口VarInterface。main类使用类型VarInterface保存变量的实例 我读过其他几个声称正确的实现,但我无法让它工作。有人知道我做错了什么吗 主类循环: while(true){

我最近发表了一篇文章,在花了几个小时摆弄不同的示例代码和阅读教程之后,我遇到了以下问题:

通过使用类加载器,我能够在运行时使用处的代码将本地变量从类
MyVar1
更改为类
MyVar2
,但我无法用另一个版本的
MyVar2
替换该类
MyVar2

MyVar1
MyVar2
都实现了一个接口
VarInterface
。main类使用类型
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;
}
公共类loadClass(字符串what){
//获取可重载类的目录(URL)
URL[]URL=null;
试一试{
//将文件对象转换为URL
File dir=新文件(System.getProperty(“user.dir”)
+File.separator+“dir”+File.separator);
URL=dir.toURL();
URL=新URL[]{URL};
}捕获(格式错误){
}
//使用目录创建一个新的类加载器
ClassLoader cl=新的URLClassLoader(URL);
//课堂上的负荷
类别cls=null;
试一试{
cls=cl.loadClass(“MyVar2”);
}catch(classnotfounde异常){
e、 printStackTrace();
}
返回cls;
}

对于前3次迭代,调用了
MyVar1.ping()
,之后调用了
MyVar2.ping()
,即使我替换了
MyVar2.class
MyVar2.java
文件。

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

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


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

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


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

只是为了澄清这个问题-让我们说
MyVar2.ping()
打印“Hello”,当
i==10
将类更改为打印“再见”时,您的问题是无论发生什么更改,您仍然会看到“Hello”,对吧?有点类似。我没有用另一个版本(如I==10)替换MyVar2的内部触发器,我只是直接替换文件或在eclipse中编辑并保存。我正在创建一个新的类加载器实例,正如您在上面的replaceVar函数中看到的那样。“大部分代码”由MyVar类中的循环和
ping()
函数组成,因为目前这只是一个沙箱实验。如果这是解决方案,你应该自己接受,这样你的问题显然已经得到了回答(尽管是你自己)。