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

时间:2013-06-16 08:37:33

标签: java stream

    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");
}

3 个答案:

答案 0 :(得分:8)

这样做是为了防止“黑客攻击”。只能通过调用native方法

的适当setter来更改这些字段
private static native void setIn0(InputStream in);
private static native void setOut0(PrintStream out);
private static native void setErr0(PrintStream err);

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

答案 1 :(得分:6)

它们稍后由原生方法设置SetIn0SetOut0SetErr0

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

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

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));

答案 2 :(得分:2)

final字段不一定是常量。它们仍然可以被操作,只是在编译时才会阻止操作,特别是阻止你使用赋值运算符(=)。请参阅this questionJLS §17.5.3,具体为:

  

final字段可以通过反射和其他依赖于实现的方式进行更改。

这对于反序列化这样的事情是必要的。这也可能引起一些有趣的警告,因为编译器可以在编译时和运行时优化final字段。上面链接的JLS就是一个例子。