在系统.java源中,标准输入、输出和错误流被声明为 final 并初始化为 null?

2022-09-03 01:08:32
public final static InputStream in = null;
public final static PrintStream out = null;
public final static PrintStream err = null;

但正如我们非常清楚的那样,默认情况下,这些流已连接到控制台并且已经打开。System 类 setIn()、setOut 和 setErr() 中也有一些方法来重定向流。当它们被声明为 final 并设置为初始化值 null 时,这怎么可能?

我编译了以下代码,在调用 println() 时设置了一个断点,并使用 netbeans 进行了调试。我的目标是通过单步执行源来确定变量 System.in 初始化为标准输出的确切时间。但是,在调用 main 方法时,输出流出似乎已经初始化。

public static void main(String[] args) {
    System.out.println("foo");
}

答案 1

这样做是为了防止“黑客攻击”。这些字段只能由调用方法的适当 setter 进行更改native

private static native void setIn0(InputStream in);
private static native void setOut0(PrintStream out);
private static native void setErr0(PrintStream err);

本机方法可以执行所有操作,包括更改最终字段。


答案 2

它们后来通过本地方法进行设置,并且SetIn0SetOut0SetErr0

private static native void setIn0(InputStream in);
private static native void setOut0(PrintStream out);
private static native void setErr0(PrintStream err);

从该方法调用,根据 JavaDoc,该方法在线程初始化后调用initializeSystemClass

FileInputStream fdIn = new FileInputStream(FileDescriptor.in);
FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err);
setIn0(new BufferedInputStream(fdIn));
setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true));
setErr0(new PrintStream(new BufferedOutputStream(fdErr, 128), true));

推荐