动态编译
1. 应用场景
可以编写一个在线评测系统,浏览器端写Java代码,上传到服务器进行编译和运行
服务器动态加载某些类文件进行编译
2. 两种做法
(1) 通过JavaCompiler动态编译
(2) 通过Runtime调用javac,启动新的进程去操作
下面对方法一进行讲解
假设有一个已经写好的.java文件存放在c:/myjava/中
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
int result = compiler.run(null, null, null, "c:/myjava/HelloWorld.java");
System.out.println(result == 0? "编译成功" : "编译失败");
执行过后在c:/myjava/中可以发现多出了一个HelloWorld.class文件,说明编译成功
这个例子就说明了,用户在浏览器端进行输入,然后在服务器端通过String字符串等编写一个临时 文件,再通过该方法进行编译,不过在实际操作过程中,需要注意安全的处理
3. 通过Runtime.getRunTime()运行编译好的类
假设程序已经编译成功,需要启动新的进程动运行
Runtime run = Runtime.getRuntime();
Process process = run.exec("java -cp c:/myjava HelloWorld");
//若是打印内容,在编译器控制台无法显示,需要读取响应的输入流
InputStream in = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String info = "";
while((info = reader.readLine()) != null){
System.out.println(info);
}
4. 通过反射运行编译好的类
在这里尤其要注意通过反射调用main()函数的问题,一定要记得转型为(Object)new String[]{},否则将会发生参数个数不匹配的问题
try {
URL[] urls = new URL[] {new URL("file:/" + "c:/myjava/")};
URLClassLoader loader = new URLClassLoader(urls);
Class c = loader.loadClass("HelloWorld");
//调用加载类的main方法
Method m = c.getMethod("main", String[].class);
m.invoke(null, (Object)new String[]{});
//m.invoke(null, new String[]{"a","b"});
//上面代码会被编译成:m.invoke(null,"a","b"),这样就发生参数个数不匹配的问题
//因此,必须加上(Object)进行转型,避免这个问题
} catch (Exception e) {
e.printStackTrace();
}
来源:CSDN
作者:yudidina
链接:https://blog.csdn.net/qq_43468570/article/details/104270836