- 对.java文件即时编译
- 对字符串即时编译
- 监听在编译过程中产生的警告和错误
- 在代码中运行编译器(并非:Runtime命令行调用javac命令)
- 自Java1.6推出,位于javax.tools包中
- 可用在程序文件中的Java编译器接口(代替javac.exe)
- 在程序中编译Java文件,产生class文件
- run方法(继承自java.tools.Tools):比较简单。可以编译Java源文件,生成class文件,但不能指定输出路径,监控报错信息,调用后就在源码所在目录生成class文件
- getTask方法:更强大的功能。可以编译Java源文件,包括在内存中的Java文件(字符串),生成class文件
// 编译成功函数 public static void successCompile() { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); // 参数1:输入流,null表示默认使用system.in // 参数2:输出流,null表示默认使用system.out // 参数3:错误流,null表示默认使用system.err // 参数4:String... 需要编译的路径 // 返回值:0表示成功,其他表示错误 int result = compiler.run(null, null, null, "E:\\TangJiachang\\java学习\\JavaDome1\\src\\exmple\\com\\demo4\\A.java"); System.out.println(0 == result ? "编译成功" : "编译失败"); }
注意:编译后的class文件和java文件在同一个目录
public static void failCompile() throws UnsupportedEncodingException { ByteArrayOutputStream err = new ByteArrayOutputStream(); JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); int result = compiler.run(null, null, null, "E:\\TangJiachang\\java学习\\JavaDome1\\src\\exmple\\com\\demo4\\B.java"); if (0 == result) { System.out.println("成功"); } else { System.out.println("失败"); System.out.println(new String(err.toByteArray(), Charset.defaultCharset().toString())); } }
由于指定的目录中没有B.java文件所以报错
public class Demo2 { public static void main(String[] args) { compileJavaFromString(); } public static void compileJavaFromString() { StringBuilder sb = new StringBuilder(); // 类名 String className = "Hello"; sb.append("public class Hello {\n"); sb.append("public static void main(String[] args) {\n"); sb.append("System.out.println(\"hello world\");\n"); sb.append("}\n"); sb.append("}"); // 将上述的代码编译 Class<?> c = compile(className, sb.toString()); try { // 生成对象 Object obj = c.newInstance(); // 调用main方法,必须传递String[].class参数 Method m = c.getMethod("main", String[].class); // 运行main方法 m.invoke(obj, new Object[] {new String[] {} }); } catch (Exception e) { e.printStackTrace(); } } private static Class<?> compile(String className, String javaCodes) { // 将字符串包装成SimpleJavaFileObject对象 JavaSourceFromString srcObject = new JavaSourceFromString(className, javaCodes); // 输出代码内容 System.out.println(srcObject.getCode()); Iterable<? extends JavaFileObject> fileObjects = Arrays.asList(srcObject); // javac.exe接口 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); // 文件管理器 StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); // 报告诊断信息对象 DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<JavaFileObject>(); //设置编译的输出目录,并包装在options中 String flag = "-d"; // 编译输出路径 String outDir = ""; try { File classPath = new File(Thread.currentThread().getContextClassLoader().getResource("").toURI()); outDir = classPath.getAbsolutePath() + File.separator; // 输出编译后的文件路径 System.out.println(outDir); } catch (URISyntaxException e1) { e1.printStackTrace(); } // 等价于javac -d outPath javaFile Iterable<String> options = Arrays.asList(flag, outDir); // JavaCompiler.getTask方法:以future的任务形式(多线程),来执行编译任务 // 第一个参数:额外输出流,null表示默认使用system.err // 第二个参数:文件管理器,null表示编译器标准文件管理器 // 第三个参数:诊断监听器,null表示使用编译器默认方法来报告诊断信息 // 第四个参数:编译器参数,null表示无参数 // 第五个参数:需要经过annotation处理的类名,null表示没有类需要annotation处理 // 第六个参数:待编译的类 JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnosticCollector, options, null, fileObjects); // 等待编译结束 boolean result = task.call(); if (result == true) { try { return Class.forName(className); } catch (ClassNotFoundException e) { e.printStackTrace(); } } else { for (Diagnostic diagnostic : diagnosticCollector .getDiagnostics()) { System.out.println("Error on line: " + diagnostic.getLineNumber() + "; URI: " + diagnostic.getSource().toString()); } } return null; } } // 由于我们的代码是一串字符串没有存储到实际的文件中 // 所以使用本类来虚拟一个文件来存储对应的code class JavaSourceFromString extends SimpleJavaFileObject { private String code; protected JavaSourceFromString(String name, String code) { super(URI.create("string:///" + name.replace(".", "/") + Kind.SOURCE.extension), Kind.SOURCE); this.code = code; } public CharSequence getCharContent(boolean ignoreEncodingErrors) { return code; } public String getCode() { return code; } }
由于对字符串的编译时,字符串是在内存中的,所以需要使用SimpleJavaFileObject这个类来虚拟一个文件用来存储对应的字符串,这样子就可以使用反射机制来读取该文件。
- Java EE的JSP编译
- 在线编译环境
- 在线程序评判系统
- 自动化的构建和测试工具