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

System.out is declared as static final and initialized with null?

当我浏览 System.class 时,我发现了一些我觉得很奇怪的东西。当您查看 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 ?

谁能解释一下已经声明为 final 的 out 是如何初始化的?

Since final can be initialized only once then how these are getting managed ?

虽然您可以通过反射更改 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);

When we use System.out.print("..."); It is obvious that out is not null but being a final static how it is not null ?

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

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

So can any one explain that how out is initialized which is already declared final ?

这是因为 final 并不像您想象的那么最终。有人建议我们需要 final final.

它是在静态初始化程序中使用本机代码初始化的。 在 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() 方法将初始化 in/out/err - 它在本机代码中这样做 - 本机代码几乎可以做任何它想做的事情并且不限于所有 java语言规则。 (虽然你也可以通过反射在 Java 中设置一个已经初始化的最终字段)