我在运行时替换jar时遇到一些问题.我捏了2个罐子全部命名A.jar
,jar只包含1个类命名A.class
,代码A.class
非常简单,第一个jar是:System.out.println("before replacement")
,第二个jar是: System.out.println("after replacement")
,我想在运行时用第二个jar替换第一个jar,所以我把第一个罐子放在下面C:
,第二个罐子放在下面C:\test\
我的代码是:
import java.lang.reflect.Method;
public class B {
public static void main(String[] args) throws Exception{
final String src = "C:\\test\\A.jar";
final String desc = "C:\\";
System.out.println("start to copy A.jar");
String cmd = "cmd /c xcopy " + src + " " + desc + " /y";
Runtime.getRuntime().exec(cmd).waitFor();
System.out.println("finish to copy A.jar");
Class<?> cls = Class.forName("A");
Object obj = cls.newInstance();
Method m = cls.getMethod("test");
m.invoke(obj, null);
/*A a = new A();
a.test();*/
}
}
Run Code Online (Sandbox Code Playgroud)
我发现了2个问题:
"after replacement"
,没关系.但是当我使用命令行运行相同的代码时,它会抛出ClassNotFoundException
.命令行有什么问题?在eclipse中我替换Java反射代码
Class<?> cls = Class.forName("A");
Object obj = cls.newInstance();
Method m = cls.getMethod("test");
m.invoke(obj, null);
Run Code Online (Sandbox Code Playgroud)
同
A a = new A();
a.test();
Run Code Online (Sandbox Code Playgroud)
输出是"before replacement"
.我认为A
应该在运行时加载类,所以当new A()
首次加载类时,那时jar已被替换,为什么输出仍然"before replacement"
和jave反射代码工作正常?
请给我一些指示.谢谢!
添加更多,我用-verbose:class打印所有类加载信息,我发现class.forname在替换完成后加载A.jar,而对于新的A(),A.jar在我的代码系统之间加载成功.out.println("开始复制A.jar")和System.out.println("完成复制A.jar").这是因为结果不同.但为什么在新的A()之前加载A.jar?
小智 1
从表面上看 - 你的 eclipse 运行在 jar 文件的同一文件夹下(即 C:\test)。因此,当您从 eclipse 运行时,程序就会执行。但是,当您从命令行运行时,您可能在不同的文件夹(可能是 C:)中打开命令窗口 - 因此它无法找到位于“C:\test”或其他文件夹中的类。也许您可以尝试从 C:\test 运行程序或在命令提示符中指向 jar 文件的位置(请参阅带有外部 .jar 的 Java 命令行)。
当您的程序加载时 - 它会加载类路径中先前的 A.jar 文件。因此,当您指向类 A ( Class<?> cls = Class.forName("A");
) 时,它会从旧 jar 文件返回 A,因为它不知道您已替换文件系统中的旧 jar。您需要重新加载内存中加载的 jar 文件 - 请参阅动态重新加载 jar 文件内容。