我正在开发类似IDE的项目,其中由用户更改的代码在运行时由JavaCompiler重新编译,需要重新加载以执行更改的代码,我使用反射来执行此操作,但问题是类曾经加载过ClassLoader在重新执行下面的代码时永远不会被更改它保持静态,但是当我退出整个应用程序并重新启动它时,我可以看到重新编译代码中的更改。以下是我正在使用的代码:
Class<?> clazz = Class.forName("Projects.Demo."+classname);
Constructor<?> ctor = clazz.getConstructor(App.class, Ctrl.class);
Object object = ctor.newInstance(new Object[] { app , ctrl});
我找到的解决方案之一是在java2s.com上,标题为“动态重新加载已修改的类”:
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
class MyClass{
public String myMethod() {
return "a message";
}
}
public class Main {
public static void main(String[] argv) throws Exception {
URL[] urls = null;
File dir = new File(System.getProperty("user.dir") + File.separator + "dir" + File.separator);
URL url = dir.toURI().toURL();
urls = new URL[] { url };
ClassLoader cl = new URLClassLoader(urls);
Class cls = cl.loadClass("MyClass");
MyClass myObj = (MyClass) cls.newInstance();
}
但它不适合我,因为更改的类永远不会被此代码重新加载。
如果有其他选择可以帮助我或建议我。
答案 0 :(得分:3)
好的,这是我必须工作的东西。
如果Myclass位于标准类路径中,请注意它不起作用。
package nz.test.loader;
public interface Executer {
public void execute();
}
package nz.test.loader;
import javax.tools.*;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
public class LoadClass {
public static void main(String[] argv) throws Exception {
URL[] urls = null;
File dir = new File(System.getProperty("user.dir") + File.separator + "out/dir" + File.separator);
File classFile = new File(dir,"nz/co.test/loader/MyClass.class");
long lastModified = classFile.lastModified();
URL url = dir.toURI().toURL();
urls = new URL[] { url };
ClassLoader cl = new URLClassLoader(urls);
compileClass("first class", dir.getAbsolutePath());
Class cls = cl.loadClass("nz.test.loader.MyClass");
Executer myObj = (Executer) cls.newInstance();
myObj.execute();
compileClass("another class", dir.getAbsolutePath());
cl = new URLClassLoader(urls);
cls = cl.loadClass("nz.test.loader.MyClass");
myObj = (Executer) cls.newInstance();
myObj.execute();
}
public static void compileClass(String message, String destination) throws IOException {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
StringWriter writer = new StringWriter();
PrintWriter out = new PrintWriter(writer);
out.println("package nz.test.loader;");
out.println("public class MyClass implements Executer{");
out.println(" public void execute() {");
out.println(" System.out.println(\""+message+"\");");
out.println(" }");
out.println("}");
out.close();
JavaFileObject file = new JavaSourceFromString("nz.test.loader.MyClass", writer.toString());
Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(file);
List<String> optionList = new ArrayList<String>();
JavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null,null);
List<String> params = new ArrayList();
params.add(destination);
fileManager.handleOption("-d",params.iterator());
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, optionList, null, compilationUnits);
boolean success = task.call();
for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
System.out.println(diagnostic.getCode());
System.out.println(diagnostic.getKind());
System.out.println(diagnostic.getPosition());
System.out.println(diagnostic.getStartPosition());
System.out.println(diagnostic.getEndPosition());
System.out.println(diagnostic.getSource());
System.out.println(diagnostic.getMessage(null));
}
System.out.println("Success: " + success);
}
}
class JavaSourceFromString extends SimpleJavaFileObject {
final String code;
JavaSourceFromString(String name, String code) {
super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension),Kind.SOURCE);
this.code = code;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return code;
}
}