奇怪的'out'变量,System.out.println()

时间:2013-03-22 08:41:14

标签: java nullpointerexception

以下是java.lang.System类(JDK版本1.6)

中的代码
public final static PrintStream out = nullPrintStream(); //out is set to 'null'

private static PrintStream nullPrintStream() throws NullPointerException {
    if (currentTimeMillis() > 0) {
        return null;
    }
    throw new NullPointerException();
}

当我们在代码中编写System.out.println("Something");时,为什么即使'out'设置为'null'也不会得到NullPointerException

无论如何out将通过系统类

中的setOut方法设置
public static void setOut(PrintStream out) {
     checkIO();
     setOut0(out);
 }

Theyn为什么JLS需要nullPrintStream方法?

3 个答案:

答案 0 :(得分:8)

查看private static void initializeSystemClass() - 调用此方法启动操作,调用setOut0()这是native方法。这将Stream绑定到它应该的位置。

即使该字段可能看起来 public static final实际上并非如此,native代码也会对其进行更改。

修改

OP问那么为什么JLS需要nullPrintStream方法?

这与java编译器有关 - 如果在编译时将它们分配给常量,它将“内联”static final字段,如null。编译器实际上会用常量替换每个对该字段的引用。

这会破坏初始化,因为对象不再包含对Stream的引用,而是null的引用。将流分配给方法的返回会阻止内联。

有些人可能称之为肮脏的黑客。错误引用俾斯麦“JDK就像香肠一样,最好不要看它的制作”。

答案 1 :(得分:2)

这就是System.out类的初始化方式。

还有一种方法:

 private static native void setOut0(PrintStream out);

在以下方法中调用:

private static void initializeSystemClass() {

答案 2 :(得分:2)

System.in,out和err由JVM从本机代码管理。使用nullPrintStream()的这整个魔法是为了让javac不要内联这些字段。从java 7开始,它看起来像

public final static PrintStream out = null;