public final static InputStream in = null;
public final static PrintStream out = null;
public final static PrintStream err = null;
Run Code Online (Sandbox Code Playgroud)
但是我们非常清楚,这些流默认连接到控制台并且已经打开.System类setIn(),setOut和setErr()中还有一些方法可以重定向流.当它们被声明为final并设置为初始化值null时,这有什么可能吗?
我编译了以下代码,在调用println()时设置断点并使用netbeans进行调试.我的目标是通过步入源来确定何时将变量System.in初始化为标准输出.但似乎输出流输出已经在调用main方法时初始化.
public static void main(String[] args) {
System.out.println("foo");
}
Run Code Online (Sandbox Code Playgroud)
这样做是为了防止"黑客攻击".只能通过调用native方法的适当setter来更改这些字段
private static native void setIn0(InputStream in);
private static native void setOut0(PrintStream out);
private static native void setErr0(PrintStream err);
Run Code Online (Sandbox Code Playgroud)
原生方法可以做任何事情,包括更改最终字段
它们后来由本机方法设置SetIn0,SetOut0并且SetErr0
private static native void setIn0(InputStream in);
private static native void setOut0(PrintStream out);
private static native void setErr0(PrintStream err);
Run Code Online (Sandbox Code Playgroud)
从被叫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));
Run Code Online (Sandbox Code Playgroud)
final场不一定是恒定的。它们仍然可以被操作,只是操作只能在编译时被阻止,特别是通过阻止您使用赋值运算符(=)。请参阅此问题和JLS \xc2\xa717.5.3,具体来说:
\n\n\n\n
final字段可以通过反射和其他依赖于实现的方式进行更改。
这对于反序列化之类的事情是必要的。这也会导致一些有趣的警告,因为编译器可以优化final在编译时和运行时优化字段。上面链接的 JLS 有一个这样的例子。