Java System.out和最终对象内联

Java System.out和最终对象内联,java,Java,正如我们都知道的那样,当只重新编译应用程序的一部分时,javac内联线常量在编译时可能会导致有趣的问题,这里的每个人都知道解决这个问题的常用方法(使javac不理解它实际上是一个编译时常量) 但是,如果我们查看oracle JDK的System.class中的代码,我们会看到以下内容: public final static PrintStream out = null; 因此,大概out是由JVM初始化中的反射或其他机制设置的。但这引出了一个问题:为什么out不在这里内联?(至少在使用Sys

正如我们都知道的那样,当只重新编译应用程序的一部分时,javac内联线常量在编译时可能会导致有趣的问题,这里的每个人都知道解决这个问题的常用方法(使javac不理解它实际上是一个编译时常量)

但是,如果我们查看oracle JDK的
System.class
中的代码,我们会看到以下内容:

public final static PrintStream out = null;
因此,大概
out
是由JVM初始化中的反射或其他机制设置的。但这引出了一个问题:为什么out不在这里内联?(至少在使用
System.out.println()
时,我从未遇到过空指针异常)


javac是否对这种情况进行了特殊处理,或者语言规范是否合理地处理了这种情况?

我的JDK代码说
out=nullInputStream()
,并对该方法进行了注释:

/**
 * The following two methods exist because in, out, and err must be
 * initialized to null. The compiler, however, cannot be permitted to
 * inline access to them, since they are later set to more sensible values
 * by initializeSystemClass().
 */

initializeSystemClass()
调用
setOut0(..)
,它是
本机的
,可能会在
最终的
中循环<代码>系统。放样(…)的工作方式相同。

静态最终构建有多种结果。文字可能是内联的 例如,
static final int xxx=1
,这一点很清楚,但例如
static final int xxx=returnOne()
可能不是

原语类型和字符串只能替换为文字,其他所有对象都不能。最后但并非最不重要的是
System.out/in
违反JLS(一旦初始化了最终字段,它总是包含相同的值)


防止内联的几种方法:
静态最终字符串xxx=“xxx”.intern()
静态最终整数yyy=123+return0()由于评估可能仅在运行时执行,javac将生成GETFIELD而不是BIPUSH(对于int)。

只内联文本“const”,其余的每次都读取-这是OpenJDK变体吗?我正在使用oracle/sun实现。@Voo、setIn和setOut在所有JDK版本中都是从1.1开始出现的(即对大多数人来说是永远存在的)。。。远早于java成为GPL兼容者。@bestsss,但bozho的代码使用的是
out=nullInputStream()
,而它对我说的是
out=null
,这是不同的。最后一个变量是如何被覆盖的并不有趣——我知道有几种不同的方法。似乎该代码的编写者也不知道JLS中仅限文字和字符串的限制;)@Voo,我不记得有哪个版本是w/
out=null
in=null
,但该字段不能用常量替换,因为它不是字符串,JVM每次都使用System.in/out的内部函数来读取它们(没有CSE[公共子表达式消除])@bestsss现在我有点想知道我的JDK源代码列表来自哪个并行世界;)安装机器时,像往常一样从oracle下载。。是的,JIT对期末考试和CSE的延迟初始化是另一个问题,这是非常相似的。这两种情况下的“错误修复”都是一样的。有趣的是,在JLS中找不到定义,但将其限制为文本和字符串可以解释为什么它在没有这些攻击的情况下工作。是的,我确实知道如何避免字符串和int的内联-我只是在代码中偶然发现了它,并惊讶于它在没有这些黑客的情况下工作。我读的第一本(也是唯一一本)关于java的书“java秘密”就谈到了这种特性,另外,这是非常明显的,因为内联任何内容的唯一方法是BIPUSH或常量表引用(我在学习“java汇编程序”时获得了这一点)