首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java SE 6編譯器API完整解析:JavaCompiler、StandardJavaFileManager、內存編譯三種模式

     編輯:Java 程式設計入門

Java SE 6引入javax.tools標準API,無需依賴tools.jar即可在程序中動態編譯、加載、運行Java代碼。

模式一:JavaCompiler簡單調用

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表示成功。

模式二:StandardJavaFileManager精細控制

支援診斷收集、編碼控制、輸出目錄指定:

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; }
}

應用場景

  • 動態規則引擎:業務規則以Java源碼存儲,運行時編譯執行
  • 腳本容器:用戶提交代碼片段即時執行(如在線判題、REPL)
  • 代碼生成框架:模板生成代碼後即時編譯驗證
  • 熱部署/熱修復:運行時替換類實現

注意事項

  1. 需JDK環境(含tools.jar),JRE無法使用
  2. 內存編譯類由系統類加載器加載,無法卸載,長期運行注意PermGen/Metaspace洩漏
  3. 安全場景需沙箱隔離(SecurityManager或獨立進程)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved