奇怪的’out’变量,System.out.println()
以下是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
将通过System类中的以下setOut
方法设置
public static void setOut(PrintStream out) { checkIO(); setOut0(out); }
Theyn为什么JLS需要nullPrintStream
方法?
看一下private static void initializeSystemClass()
– 这个方法被调用来启动它,它调用setOut0()
这是一个native
方法。 这将Stream
到它应该的位置。
因此即使该字段可能看起来是 public static final
它实际上不是,本native
代码也会改变它。
编辑
OP问为什么JLS需要nullPrintStream方法?
这与java编译器有关 – 如果在编译时将它们分配给常量,它将“内联” static final
字段,如null
。 编译器实际上会用常量替换每个对该字段的引用。
这将破坏初始化,因为对象将不再保持对Stream
的引用,而是为null
。 将流分配给方法的返回会阻止内联。
有人可能称之为肮脏的黑客。 错误引用俾斯麦“JDK就像香肠一样,最好不要看它被制作”。
System.in,out和err由JVM从本机代码管理。 使用nullPrintStream()的这整个魔法是为了让javac不要内联这些字段。 从java 7看起来像
public final static PrintStream out = null;
这就是System.out类的初始化方式。
还有一种方法:
private static native void setOut0(PrintStream out);
在以下方法中调用:
private static void initializeSystemClass() {
- 在Google Guava(Java)中,为什么Iterables.getFirst()和getLast()不一致?
- 如何检测字节数组中的字符串结尾到字符串转换?
- 何时使用catch以及何时在exception处理中使用throws
- Jersey – 在调用context.proceed()之前获取Interceptor中OutputStream的内容
- 无法在javascript中向java Web服务(泽西岛)发出CORS POST请求?
- Selenium – 如何计算表中的行数?
- 使用TIMESTAMPDIFF的JPA Hibernate公式中的SQL Literal
- 如何在JAVA中使用selenium接受firefox webdriver上的下载提示?
- TestNG迭代测试数据而不是测试方法