从通过反射调用的 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
或者最好是 Appendable
或Writer
,并会写入此作家。然后可以制作一个简单的单行代码 main
,只需将 System.out
扔给编写器,然后将其交给您尝试 运行 的代码,以防您只需要该代码到 运行 并写入 sysout,您可以创建自己的(并停止使用反射来调用该主要方法)并将其交给这段代码,您在这种情况下 运行ning。
请注意,您的反射代码 'works' 但是很奇怪。无需创建新实例; main
是静态的。正确的做法是:
Method method = clasz.getMethod("main", String[].class);
method.invoke(null, new String[1]);
main()
方法在同一进程中被调用,因此,您可以在反射魔法 之前通过 java.lang.System.setOut(PrintStream)
提供自己的标准输出 implementation/decorator
- 一个空字符串数组可以工作:
new String[1]
-> new String[0]
- 您不需要创建新对象来调用静态方法。尽管 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
对象上调用的
我正在通过反射调用 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
或者最好是 Appendable
或Writer
,并会写入此作家。然后可以制作一个简单的单行代码 main
,只需将 System.out
扔给编写器,然后将其交给您尝试 运行 的代码,以防您只需要该代码到 运行 并写入 sysout,您可以创建自己的(并停止使用反射来调用该主要方法)并将其交给这段代码,您在这种情况下 运行ning。
请注意,您的反射代码 'works' 但是很奇怪。无需创建新实例; main
是静态的。正确的做法是:
Method method = clasz.getMethod("main", String[].class);
method.invoke(null, new String[1]);
main()
方法在同一进程中被调用,因此,您可以在反射魔法 之前通过 - 一个空字符串数组可以工作:
new String[1]
->new String[0]
- 您不需要创建新对象来调用静态方法。尽管 java 允许通过对象调用静态方法,但这是一种糟糕的风格,有时可能会因为名称隐藏而导致问题。考虑以下示例:
java.lang.System.setOut(PrintStream)
提供自己的标准输出 implementation/decorator
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
对象上调用的