package test97;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class CompileClassLoader extends ClassLoader {
//读取一个文件的二进制内容
private byte[] getBytes(String filename) throws IOException {
File file = new File(filename);
long len = file.length();
byte[] raw = new byte[(int)len];
FileInputStream fis = new FileInputStream(file);
int r = fis.read(raw);
if (r != len) {
throw new IOException("无法加载全部文件");
}
fis.close();
return raw;
}
//定义编译指定java文件的方法
private boolean compile(String javaFile) throws IOException {
System.out.println("CompileClassLoader正在编译:" + javaFile + ".....");
//调用系统的javac命令
Process p = Runtime.getRuntime().exec("javac " + javaFile);
try {
//其他线程都等待这个线程完成
p.waitFor();
} catch (InterruptedException e) {
System.out.println(e);
}
//获取javac线程退出值
int ret = p.exitValue();
//返回编译是否成功
return ret == 0;
}
//重写ClassLoader的findClass方法
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class<?> clazz = null;
//将包路径中的"."替换为"/"
String fileStub = name.replace(".", "/");
String javaFilename = fileStub + ".java";
String classFilename = fileStub + ".class";
File javaFile = new File(javaFilename);
File classFile = new File(classFilename);
/**
* 当指定的java源文件存在,且class文件不存在,
* 或者java源文件的修改时间比class文件的修改时间晚时,重新编译
*/
if (javaFile.exists() && (!classFile.exists())
|| javaFile.lastModified()>classFile.lastModified()) {
try {
//如果编译失败或者class文件不存在
if (!compile(javaFilename) || !classFile.exists()) {
throw new ClassNotFoundException("class not found exception" + javaFilename);
}
} catch (IOException e) {
e.printStackTrace();
}
}
if (classFile.exists()) {
try {
//将class文件的二进制数据读入数组中
byte[] raw = getBytes(classFilename);
//调用ClassLoader的defineClass方法将二进制数据转换成Class对象
clazz = defineClass(name,raw,0,raw.length);
} catch (IOException e) {
e.printStackTrace();
}
}
if (clazz == null) {
throw new ClassNotFoundException(name);
}
return clazz;
}
public static void main(String[] args) throws Exception {
//如果运行该程序时没有参数,即没有目标类
if (args.length < 1) {
System.out.println("缺少运行的目标类,请按如下格式运行java源文件");
System.out.println("java CompileClassLoader ClassName");
}
//第一个参数是要运行的类
String progClass = args[0];
System.out.println(progClass);
//剩下的参数将作为运行目标时的参数,所以将这些参数复制到一个新的数组中
String progArray[] = new String[args.length-1];
System.arraycopy(args, 1, progArray, 0, progArray.length);
CompileClassLoader ccl = new CompileClassLoader();
//加载需要运行的类
Class<?> clazz = ccl.loadClass(progClass);
//获取运行类的主方法
Method main = clazz.getMethod("show", new Class[]{});
System.out.println((new String[0]).getClass());
Object argsArray[] = {progArray};
//main.invoke(null, argsArray);
ccl.invokeMethod(main, argsArray);
}
public void invokeMethod(Method main, Object argsArray[]) throws InvocationTargetException, IllegalAccessException, InstantiationException {
main.invoke(new StaticTest(), null);
}
}
参考书籍:疯狂java讲义