我知道我遗漏了一些基本的东西。我正在尝试动态编译一个类,然后在更改后重新加载它。以下代码有效。但是,当我调用它两次(更改.java后一次)时,类定义不会更新。我错过了什么?
File file = new File("/eraseme/Eraseme.java");
File[] files = new File[] {file};
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjects(files);
CompilationTask task = compiler.getTask(null, fileManager, null, null,null,compilationUnits);
boolean madeIt = task.call(); // works
File classFile = new File("/eraseme/Eraseme.class");
URL url = classFile.toURL();
URL[] urls = new URL[] { url };
ClassLoader cl = new URLClassLoader(urls);
Class cls = cl.loadClass("Eraseme");
TestApi test = (TestApi) cls.newInstance();
System.out.println(test.getVersion());
答案 0 :(得分:2)
您遗漏的是传递给URLClassLoader
的网址应该是搜索到的目录。发生的事情是你正在构建的URLClassLoader
实际上并没有找到.class文件,但是找不到类并且正在回到让父类加载器加载类。
具体来说,尝试将代码的第二位修改为:
File classFile = new File("/eraseme");
URL url = classFile.toURL();
URL[] urls = new URL[] { url };
ClassLoader cl = new URLClassLoader(urls);
Class cls = cl.loadClass("Eraseme"); // will try to load /eraseme/Eraseme.class
TestApi test = (TestApi) cls.newInstance();
System.out.println(test.getVersion());
请注意,如果您的类(包含)com.mycompany.erasestuff.EraseMe
被调用,则类加载器将查找文件/eraseme/com/mycompany/erasestuff/EraseMe.class
请注意,执行此操作时,您不希望系统类加载器能够加载EraseMe
类。系统类加载器优先,您的URLClassloader
不会加载任何内容。 (不幸的是,当你对类加载器说“加载这个类”时,首先检查它的父类加载器是否可以加载该类,然后它会尝试自己加载它。如果系统类加载器可以加载这个类,你永远不会得到不同的版本)