System.out声明为static final并用null初始化?

当我通过System.class我发现了一些对我来说很奇怪的东西。 当您查看System.in, System.out, System.err的声明时System.in, System.out, System.err这些声明为final static但也使用null初始化

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

由于final只能初始化一次然后如何管理?
当我们使用System.out.print("..."); 很明显, out不是null而是final static如何不为null

那么任何人都可以解释如何初始化已经宣布为最终的?

它在静态初始化程序中使用本机代码初始化。 在System.java的顶部,你有:

 /* register the natives via the static initializer. * * VM will invoke the initializeSystemClass method to complete * the initialization for this class separated from clinit. * Note that to use properties set by the VM, see the constraints * described in the initializeSystemClass method. */ private static native void registerNatives(); static { registerNatives(); } 

registerNatives()方法将在/ out / err中初始化 – 它在本机代码中这样做 – 本机代码几乎可以做任何想做的事情,并且不限于所有的java语言规则。 (虽然你也可以通过reflection在Java中设置已经初始化的最终字段)

由于final只能初始化一次然后如何管理?

虽然您可以通过reflection更改static final变量,但在这种情况下,字段会通过本机方法更改。

来自java.lang.System

 public static void setIn(InputStream in) { checkIO(); setIn0(in); } // same for setOut(), setErr() private static native void setIn0(InputStream in); private static native void setOut0(PrintStream out); private static native void setErr0(PrintStream err); 

当我们使用System.out.print(“…”); 很明显,out不是null,而是最终的静态如何不为null?

它在您有机会使用之前就已设置好。

你可能想知道它为什么这样做? 答案几乎肯定与加载的订单类有关。 许多类按顺序启动,但需要按照有效的顺序进行初始化。

那么任何人都可以解释如何初始化已经宣布为最终的?

这是因为final并不像你想象的那样最终。 有人建议我们需要进行final final