我们都知道javac在编译时内联常量,当只重新编译应用程序的各个部分时,这会导致一些有趣的问题,这里的每个人都知道通常的解决方案(使得javac不理解它实际上是编译时间)常数)
但是如果我们查看oracle JDK的System.class
中的代码,我们会看到以下内容:
public final static PrintStream out = null;
因此,假设out
是由JVM初始化中的反射或其他机制设置的。但这导致了一个问题:为什么不在这里进行内联? (至少我在使用System.out.println()
时从未得到空指针异常)。
javac是特殊情况,那个场景还是实际上是由语言规范处理的?
答案 0 :(得分:1)
我的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(..)
native
,可能会绕final
进行调用。 System.setOut(..)
的工作方式相同。
答案 1 :(得分:1)
static final
构造有多种结果。文字可能会被内联
例如static final int xxx = 1
,因为它很清楚,但例如static final int xxx = returnOne()
可能不是。
原始类型和字符串只能用文字替换,其他所有对象都不能。最后但并非最不重要的是System.out/in
违反了JLS(一旦最终字段被初始化,它总是包含相同的值。)。
阻止内联的几种方法:static final String xxx="xxx".intern();
或static final int yyy=123+return0();
,因为评估可能只在运行时执行,javac将生成GETFIELD而不是BIPUSH(对于int)。