【Java基础】动态编译
2018-10-22 本文已影响0人
灰色孤星
源代码:https://gitee.com/AgentXiao/reflection
动态编译要点:
1、使用场景(在线代码测评)
2、动态编译的两种方式
3、动态运行编译好的文件的两种方式
一、使用场景
在程序运行过程中,需要再次编译其他的程序。比如在线测评系统,要求在线对java文件进行编译和运行。
二、实现动态编译
动态编译的实现有两种做法:
1、通过Runtime调用javac,启动新的进程去操作。
Runtime run = Runtime.getRuntime();
Process process = run.exec("javac d:/test/test.java");
2、通过JavaCompiler动态编译。
/**
* @ClassName Demo01
* @Description 测试动态编译
* @Author xwd
* @Date 2018/10/21 21:42
*/
public class Demo01 {
public static void main(String[] args) {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
int result = compiler.run(null,null,null,"D:/test/a.java");
System.out.println(result == 0 ? "编译成功" : "编译失败");
}
}
由于文件名为a.java,但是定义了public class test,这是错误的,因此:
编译失败将文件名修改为test.java后编译成功,生成了class文件。
编译成功生成class文件三、动态运行编译好的类
1、通过Runtime.getRuntime()运行启动新的进程运行
/**
* @ClassName Demo03
* @Description 动态运行编译好的类
* @Author xwd
* @Date 2018/10/22 10:44
*/
public class Demo03 {
public static void main(String[] args) throws IOException {
Runtime run = Runtime.getRuntime();
//run.exec("javac d:/test/test.java");
Process process = run.exec("java -cp d:/test/ test");
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
String info = "";
while((info = br.readLine()) != null){
System.out.println(info);
}
}
}
2、通过反射运行编译好的类
/**
* @ClassName Demo04
* @Description 通过反射运行编译好的类
* @Author xwd
* @Date 2018/10/22 10:52
*/
public class Demo04 {
public static void main(String[] args) throws Exception {
runJavaClassByReflect("D:/test/","test");
}
public static void runJavaClassByReflect(String dir,String classFile) throws Exception{
try {
//通过url获得Class类对象
URL[] urls = new URL[] {new URL("file:/"+dir)};
URLClassLoader loader = new URLClassLoader(urls);
Class c = loader.loadClass(classFile);
//调用加载类的main方法(必须使用Object转型)
c.getMethod("main",String[].class).invoke(null,(Object)new String[]{});
} catch (Exception e) {
e.printStackTrace();
}
}
}
这里需要注意的是:
由于可变参数是JDK1.5之后才有的,因此在
c.getMethod("main",String[].class).invoke(null,(Object)new String[]{"aa","bb"});
中,如果不加(Object)进行强制转型的话,编译器会编译成:
.invoke(null,"aa","bb");
但是main方法的参数是字符串数组,会发生不匹配问题。
错误参数个数异常因此必须使用(Object)进行强制转型,避免这个问题。