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");
}
答案 0 :(得分:8)
这样做是为了防止“黑客攻击”。只能通过调用native
方法
private static native void setIn0(InputStream in);
private static native void setOut0(PrintStream out);
private static native void setErr0(PrintStream err);
本机方法可以执行所有操作,包括更改最终字段。
答案 1 :(得分:6)
它们稍后由原生方法设置SetIn0
,SetOut0
和SetErr0
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 question和JLS §17.5.3,具体为:
final
字段可以通过反射和其他依赖于实现的方式进行更改。
这对于反序列化这样的事情是必要的。这也可能引起一些有趣的警告,因为编译器可以在编译时和运行时优化final
字段。上面链接的JLS就是一个例子。