6

以下是 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将通过setOutSystem 类中的以下方法设置

public static void setOut(PrintStream out) {
     checkIO();
     setOut0(out);
 }

他们为什么 JLS 需要nullPrintStream方法?

4

3 回答 3

8

看一下private static void initializeSystemClass()——这个方法被调用来启动东西,它调用了setOut0()哪个native方法。这与Stream它应该在的地方联系在一起。

因此,即使该字段看起来 public static final实际上不是,native代码也会更改它。

编辑

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

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

这将破坏初始化,因为对象将不再持有对的引用,Stream而是对null. 将流分配给方法的返回可以防止内联。

有些人可能会称其为肮脏的黑客行为。错误地引用俾斯麦“JDK 就像香肠,最好不要看到它被制造出来”。

于 2013-03-22T08:46:32.677 回答
2

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

还有一种方法:

 private static native void setOut0(PrintStream out);

在以下方法中调用:

private static void initializeSystemClass() {
于 2013-03-22T08:42:52.773 回答
2

System.in、out 和 err 由 JVM 从本机代码管理。nullPrintStream() 的全部魔力是为了防止 javac 内联这些字段。从 java 7 开始,它看起来像

public final static PrintStream out = null;
于 2013-03-22T08:47:47.203 回答