注意:
1.动态编译的class文件不要放到jre的ClassPath中,在jre在ClassPath中找到的类只会加载一次。
2.使用反射获取类的时,如果需要获取最新生成的,需要重新实例化一个类加载器,因为旧的类加载器已经加载过这个类,再次加载只会加载上次那个。而重新实例化的类加载器没有加载过这个类,所以会重新去定义、链接和加载。
Main.java
public class Main { public static void main(String[] args) { String fullClassName = "MyObj"; String code = "public class MyObj implements MyInterface{public void sayHello(){System.out.println(666);}}"; String code_2 = "public class MyObj implements MyInterface{public void sayHello(){System.out.println(777);}}"; String code_3 = "public class MyObj implements MyInterface{public void sayHello(){System.out.println(888);}}"; load(code,fullClassName); load(code_2,fullClassName); load(code_3,fullClassName); } private static void load(String code, String fullClassName) { new MyClassCompiler(fullClassName, code).compile(); try { MyInterface myObj = (MyInterface) new MyClassLoader().loadClass( fullClassName).newInstance(); myObj.sayHello(); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
MyClassCompiler.java
import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.Arrays; import javax.tools.JavaCompiler; import javax.tools.JavaCompiler.CompilationTask; import javax.tools.JavaFileObject; import javax.tools.JavaFileObject.Kind; import javax.tools.SimpleJavaFileObject; import javax.tools.ToolProvider; public class MyClassCompiler { private String simpleClassName; private String code; private String classPath = System.getProperty("user.dir") + File.separator + "myFolder"; public MyClassCompiler(String simpleClassName, String code) { this.simpleClassName = simpleClassName; this.code = code; } public boolean compile() { try { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); JavaFileObject javaFile = new SimpleJavaFileObject(new URI( simpleClassName + ".java"), Kind.SOURCE) { @Override public CharSequence getCharContent(boolean arg) throws IOException { return code; } }; CompilationTask task = compiler.getTask(null, null, null, Arrays.asList("-d", classPath), null, Arrays.asList(javaFile)); return task.call(); } catch (URISyntaxException e) { e.printStackTrace(); return false; } } public String getSimpleClassName() { return simpleClassName; } public void setSimpleClassName(String simpleClassName) { this.simpleClassName = simpleClassName; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getClassPath() { return classPath; } public void setClassPath(String classPath) { this.classPath = classPath; } }
MyClassLoader.java
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; public class MyClassLoader extends ClassLoader { private boolean alwaysDefineClass = true; private String classPath = System.getProperty("user.dir") + File.separator + "myFolder"; @Override protected Class<?> findClass(String fullClassName) throws ClassNotFoundException { Class<?> clazz = null; // clazz = findLoadedClass(fullClassName); // if(alwaysDefineClass || clazz == null){ byte[] raw = readClassBytes(fullClassName); clazz = defineClass(fullClassName, raw, 0, raw.length); resolveClass(clazz); // } return clazz; } private byte[] readClassBytes(String fullClassName) { byte[] raw = null; InputStream stream = null; File file = new File(classPath + File.separator + fullClassName.replaceAll("\\.", "/") + ".class"); try { stream = new FileInputStream(file); raw = new byte[(int) file.length()]; stream.read(raw); } catch (Exception e) { } finally { try { stream.close(); } catch (IOException e) { } } return raw; } public boolean isAlwaysDefineClass() { return alwaysDefineClass; } public void setAlwaysDefineClass(boolean alwaysDefineClass) { this.alwaysDefineClass = alwaysDefineClass; } public String getClassPath() { return classPath; } public void setClassPath(String classPath) { this.classPath = classPath; } }
interface.java
public interface MyInterface { public void sayHello(); }