运行 来自 java 代码和捕获输出的已编译 java .class 文件

Running a compiled java .class file from within java code and capturing output

我正在尝试编写一个 java 程序,其界面允许用户创建 .java 文件并编译和 运行 它(本质上是一个非常简单的 IDE).我正在为 gui 使用 java swing,到目前为止,我已经能够将界面中的 .java 文件编译成 .class 文件。我一直在研究如何从 java 代码中 运行 一个 .class 文件,但找到了很多我无法开始工作的答案。下面是编译的相关代码:

File javaFile = new File( "test1.java" );
String code = entry.getText(); // get text entered by user in GUI
try{
  PrintWriter writer = new PrintWriter( javaFile );  // write text to .java file  
  writer.print( code );
  writer.close();
}
catch( FileNotFoundException e ){
  System.err.println( e );
}
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
List<File> sourceFileList = new ArrayList<File>();
sourceFileList.add( javaFile );
StandardJavaFileManager fileManager = compiler.getStandardFileManager( null, null, null );
Iterable<? extends JavaFileObject> javaSource = fileManager.getJavaFileObjectsFromFiles( sourceFileList );
CompilationTask task = compiler.getTask(null, fileManager, null, null, null, javaSource);
task.call(); // compile .java file into .class file

如何 运行 编译后的 .class 文件并在我的代码中捕获其输出?

编译完成后,您需要加载 Class 对象,然后调用 main(String[]) 方法。要捕获标准输出,您需要使用 System.setOut.

private String invokeClass(String className) throws URISyntaxException, IOException, ReflectiveOperationException {
    Class<?> clazz = Class.forName(className);
    // Alternatively, you can load the new class with a new Classloader, if you don't want to pollute the current Classloader
    // Class<?> clazz = new URLClassLoader(new URL[]{getClass().getClassLoader().getResource("").toURI().toURL()}, getClass().getClassLoader()).loadClass(className);
    Method main = clazz.getDeclaredMethod("main", String[].class);
    try ( ByteArrayOutputStream out = new ByteArrayOutputStream();
          PrintStream ps = new PrintStream(out)) {
        System.setOut(ps);
        main.invoke(main, new Object[]{new String[0]});
        return out.toString();
    }
    finally {
        // Reset to the console
        System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out)));
    }
}