从通过反射调用的 main 方法中获取 System.out.println 的值

Get value of System.out.println from main method called via reflection

我正在通过反射调用 class 的主要方法。例如:

Object o = clasz.getDeclaredConstructor().newInstance();
Method method = clasz.getMethod("main", String[].class);
method.invoke(o, new String[1]);

调用的代码如下所示:

public class Test {
    public static void main(String[] args) {
        System.out.println("This is a test");
    }
}

反射正常,我可以在控制台中看到消息。

有没有办法注册方法调用的绑定之类的东西,例如 PrintWriter 或自定义修饰的 Writer,这样我就可以将打印值作为字符串获取?

您可以使用 System.setOut(); 更改 System.out 绑定的内容。然后你可以自己制作:

public class MyTeeingPrinter extends OutputStream {
    private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    private final PrintStream original;

    public MyTeeingPrinter(PrintStream original) {
        this.original = original;
    }

    @Override public void write(int b) {
        original.write(b);
        buffer.write(b);
    }

    public String getAndClear() {
        String s = buffer.toString(StandardCharsets.UTF_8);
        buffer.reset();
        return s;
    }
}

然后:

MyTeeingPrinter tee = new MyTeeingPrinter();
System.setOut(new PrintStream(tee));

现在您可以调用 tee.getAndClear().

这有点麻烦,因为无论您像这样 运行 编写什么代码,都可能设计得很糟糕 - 它应该取而代之的是 PrintStream 或者最好是 AppendableWriter,并会写入此作家。然后可以制作一个简单的单行代码 main,只需将 System.out 扔给编写器,然后将其交给您尝试 运行 的代码,以防您只需要该代码到 运行 并写入 sysout,您可以创建自己的(并停止使用反射来调用该主要方法)并将其交给这段代码,您在这种情况下 运行ning。

请注意,您的反射代码 'works' 但是很奇怪。无需创建新实例; main 是静态的。正确的做法是:

Method method = clasz.getMethod("main", String[].class);
method.invoke(null, new String[1]);
  1. main() 方法在同一进程中被调用,因此,您可以在反射魔法
  2. 之前通过 java.lang.System.setOut(PrintStream) 提供自己的标准输出 implementation/decorator
  3. 一个空字符串数组可以工作:new String[1] -> new String[0]
  4. 您不需要创建新对象来调用静态方法。尽管 java 允许通过对象调用静态方法,但这是一种糟糕的风格,有时可能会因为名称隐藏而导致问题。考虑以下示例:
public class Parent {

    public static void main(String[] args) {
        Parent child = new Child();
        child.test();
    }

    public static void test() {
        System.out.println("Parent.test()");
    }
}

class Child extends Parent {

    public static void test() {
        System.out.println("Child.test()");
    }
}

它实际上调用了 Parent.test(),即使它是在 Child 对象上调用的