Java SE 6引入javax.tools標準API,無需依賴tools.jar即可在程序中動態編譯、加載、運行Java代碼。
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
// 編譯文件,使用標準輸入輸出
int result = compiler.run(null, null, null, "Test.java");
System.out.println(result == 0 ? "編譯成功" : "編譯失敗");
run(InputStream in, OutputStream out, OutputStream err, String... args)返回0表示成功。
支援診斷收集、編碼控制、輸出目錄指定:
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
// 構建編譯單元
Iterable<? extends JavaFileObject> compilationUnits =
fileManager.getJavaFileObjectsFromStrings(Arrays.asList("Test.java"));
// 編譯任務
JavaCompiler.CompilationTask task = compiler.getTask(
null, fileManager, diagnostics, null, null, compilationUnits);
boolean success = task.call();
fileManager.close();
// 輸出詳細診斷
for (Diagnostic<? extends JavaFileObject> d : diagnostics.getDiagnostics()) {
System.out.printf("Code: %s%nKind: %s%nPosition: %s%nMessage: %s%n",
d.getCode(), d.getKind(), d.getPosition(), d.getMessage(null));
}
// 指定輸出目錄
Iterable<String> options = Arrays.asList("-d", "D:/output");
// 指定源碼路徑
Iterable<String> options = Arrays.asList("-sourcepath", "D:/src");
無磁盤I/O,直接編譯字符串並反射調用:
public class MemoryCompileDemo {
public static void main(String[] args) throws Exception {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
// 構建源碼字符串
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
pw.println("public class HelloWorld {");
pw.println(" public static void main(String[] args) {");
pw.println(" System.out.println(\"Hello, World\");");
pw.println(" }");
pw.println("}");
pw.close();
// 自定義JavaFileObject
JavaFileObject file = new JavaSourceFromString("HelloWorld", sw.toString());
Iterable<? extends JavaFileObject> units = Arrays.asList(file);
JavaCompiler.CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, units);
boolean success = task.call();
System.out.println("Success: " + success);
if (success) {
// 反射調用
Class.forName("HelloWorld")
.getDeclaredMethod("main", String[].class)
.invoke(null, (Object) new String[]{});
}
}
}
// 內存源碼載體
class JavaSourceFromString extends SimpleJavaFileObject {
private final String code;
JavaSourceFromString(String name, String code) {
super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
this.code = code;
}
@Override public CharSequence getCharContent(boolean ignoreEncodingErrors) { return code; }
}
tools.jar),JRE無法使用