In the System.java source, the standard input, out

2019-01-19 12:01发布

    public final static InputStream in = null;
    public final static PrintStream out = null;
    public final static PrintStream err = null;

But as we very well know, these streams are connected to the console by default and already open. There are also methods in the System class setIn(), setOut, and setErr() to redirect the streams. How is any of this possible when they have been declared final and set to the initialization value null?

I compiled the following code, set a breakpoint at the call to println() and debugged using netbeans. My objective was to determine exactly when the variable System.in is initialized to the standard output by stepping into the source. But it seems that the output stream out is already initialized by the time the main method is called.

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

标签: java stream
3条回答
太酷不给撩
2楼-- · 2019-01-19 12:29

They are later on set by native methods SetIn0, SetOut0 and SetErr0

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

called from the initializeSystemClass method, which according to the JavaDoc is called after thread initialization.

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));
查看更多
一夜七次
3楼-- · 2019-01-19 12:40

This is done in order to prevent "hacking". These fields can be changed only by appropriate setters that call native methods

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

Native methods can do everything including changing final fields.

查看更多
forever°为你锁心
4楼-- · 2019-01-19 12:42

final fields are not necessarily constant. They can still be manipulated, it's just that manipulation is only prevented at compile-time, specifically by preventing you from using the assignment operator (=). See this question and JLS §17.5.3, specifically:

final fields can be changed via reflection and other implementation-dependent means.

This is necessary for things like deserialization. This can also cause some interesting caveats since compilers can optimize final fields on compile-time and run-time. The JLS linked above has an example of this.

查看更多
登录 后发表回答