Java从jdk6.0开始引入了动态编译机制
动态编译引用场景:
- 可以做一个浏览器端编写java代码,上传服务器和运行的在线评测系统
- 服务器动态加载某些类文件进行编译
动态编译做法:
- 通过 Runtime调用javac 启动新的进程去操作
- 通过JavaCompiler进行动态编译
--通过反射编运行编译好的类
示例 1 通过Runtime调用javac 启动新的进程去操作
package compiler; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import javax.tools.JavaCompiler; import javax.tools.ToolProvider; public class RuntimeTest { public static void main(String[] args) throws IOException { Runtime run = Runtime.getRuntime(); // 获取runtime对象 Process process = run.exec("java -cp e:/szw/myjava");// 编译 InputStream in = process.getInputStream(); // 根据process后去输入流,用于打印输出到控制台 BufferedReader reader = new BufferedReader(new InputStreamReader(in)); String info = ""; while ((info = reader.readLine()) != null) { System.out.println(info); } } }
示例二 通过JavaCompiler进行动态编译
package compiler; import javax.tools.JavaCompiler; import javax.tools.Tool; import javax.tools.ToolProvider; public class CompilerTest { public static void main(String[] args) { JavaCompiler jc = ToolProvider.getSystemJavaCompiler(); int flg = jc.run(null, null, null, "e:/szw/myjava.java");// 返回int 如果是0编译成功其他编译失败 // 第一个参数:为java编译器提供参数 // 第二个参数:得到java编译器的输出信息 // 第三个参数:接受编译器的错误信息 // 第四个参数:可变参数(是一个String数组)能传入一个或多个java源文件 // 返回值:0表示编译成功,非0表示编译失败 System.out.println(flg == 0 ? "编译成功" : "编译失败"); } }
--通过反射编运行编译好的类
package compiler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.net.URLClassLoader; public class UrlClassL { public static void main(String[] args) throws MalformedURLException, ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { URL[] url = new URL[] { new URL("file:/" + "e:/szw/") }; URLClassLoader loader = new URLClassLoader(url); // 调用类加载的main方法 Class c = loader.loadClass("myjava"); Method method = c.getMethod("main", String[].class); method.invoke(null, (Object) new String[] { "b", "c" });// 因为main方法是静态方法,不需要对象,所以可以为空 // 传参时,将String数组转为 object ,如果不转,编译器会把 它变成这样的一个调用 invoke(null,"b","c") // 以多个参数的形式传入,会报错,因此必须要加上 } }