Java动态编译和类的重新加载

注意:

1.动态编译的class文件不要放到jre的ClassPath中,在jre在ClassPath中找到的类只会加载一次。
2.使用反射获取类的时,如果需要获取最新生成的,需要重新实例化一个类加载器,因为旧的类加载器已经加载过这个类,再次加载只会加载上次那个。而重新实例化的类加载器没有加载过这个类,所以会重新去定义、链接和加载。


Java动态编译和类的重新加载_第1张图片

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();
}




你可能感兴趣的:(java,动态编译,类的重新加载)