Java 透過 com.sun.tools.javac.Main 可在執行期動態編譯原始碼並透過反射載入執行。本文展示一個完整的 RuntimeCode 類別,可從標準輸入讀取 Java 程式碼片段,自動包裝成類別、編譯、載入並呼叫 main()。
import java.io.*;
import java.lang.reflect.Method;
import com.sun.tools.javac.Main;
public class RuntimeCode {
private static Main javac = new Main();
public static void main(String[] args) throws Exception {
String code = "";
DataInputStream bd = new DataInputStream(System.in);
byte[] brray = new byte[200];
int i = bd.read(brray);
code = new String(brray, 0, i);
run(compile(code));
System.out.print(code);
}
private synchronized static File compile(String code) throws Exception {
File file = File.createTempFile("JavaRuntime", ".java",
new File(System.getProperty("user.dir")));
System.out.println(System.getProperty("user.dir"));
String filename = file.getName();
String classname = getClassName(filename);
PrintWriter out = new PrintWriter(new FileOutputStream(file));
out.write("class " + classname + "{" +
"public static void main(String[] args)" +
"{");
out.write(code);
out.write("}}");
out.flush();
out.close();
String[] args = new String[] { "-d",
System.getProperty("user.dir"), filename };
int status = javac.compile(args);
System.out.println(status);
return file;
}
private static synchronized void run(File file) throws Exception {
String filename = file.getName();
String classname = getClassName(filename);
new File(file.getParent(), classname + ".class").deleteOnExit();
try {
Class> cls = Class.forName(classname);
Method main = cls.getMethod("main", new Class[] { String[].class });
main.invoke(null, new Object[] { new String[0] });
} catch (SecurityException se) {
// 忽略安全例外
}
}
private static void debug(String msg) {
System.err.println(msg);
}
private static String getClassName(String filename) {
return filename.substring(0, filename.length() - 5); // 移除 .java
}
}
System.in 讀取最多 200 位元組的 Java 程式碼字串。compile():
.java 檔(前綴 JavaRuntime)。class X { public static void main(...) { ... } } 中。com.sun.tools.javac.Main.compile() 編譯,-d 指定輸出目錄為工作目錄。File 物件。run():
.class 檔。Class.forName() 載入類別。main(String[]) 方法並 invoke() 執行。com.sun.tools.javac.Main(Sun/Oracle JDK 內部 API),非標準 API,不同 JDK 實作可能不可用(如 OpenJDK 需額外模組)。BufferedReader 讀取完整輸入。main() 方法的程式碼片段,非完整類別定義。--add-modules jdk.compiler 或使用標準 javax.tools.JavaCompiler API(建議做法)。JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null);
// ... 使用 JavaFileObject 傳入字串原始碼編譯
此為標準 API,不依賴內部類別,相容性更佳。