Java常量表达式和代码消除

时间:2014-05-22 21:02:46

标签: java compiler-construction dead-code constant-expression code-elimination

正如here所述,javac和其他Java编译器可能为if - 条件为"Constant Expression"的语句提供代码消除功能。

如果我的代码使用依赖于在不同包中定义的其他常量表达式的常量表达式,这会受到什么影响?

例如,假设我在相应的指定包中有以下类:

package foo;

public class Foo {
    public static final boolean CONDITION = false;
}

package bar;

import foo.Foo;

public class Bar {
    public void test() {
        if (Foo.CONDITION) {
            System.out.println("This line of code could be eliminated.");
        } else {
            System.out.println("This line of code will be executed.");
        }
    }
}

显然,如果foo - 包是在运行时从外部jar文件加载的,那么编译器在技术上不能假设Foo.CONDITION将为false并且不应该消除{ {1}} - true - 语句的分支。

然而,如果ifFoo实际上在同一个包中,那么Bar - 分支肯定会被删除(如果编译器支持代码消除的话)。

不太确定如何最好地表达这个问题,但是:true对于Foo中的常量表达式Bar的“关闭”程度如何也被视为常量Foo?他们需要在同一个档案中吗?同样的包裹?相同的jar文件?或者它根本不重要(即编译器是否总是将Bar视为常量并使用编译时在构建路径中找到的值)?

2 个答案:

答案 0 :(得分:8)

由于它是引用类的公共“签名”的一部分,因此它被假定为常量。基本上这个想法是final意味着最终,如果你改变它,那就是你的错。

这类似于引用类的实际方法签名,也在编译时按原样使用。这就是为什么如果您针对一个版本的库编译代码并针对另一个版本运行它,您可能会获得NoSuchMethodError

更新:实际上是JLS gives an even stronger guarantee

  

如果字段是常量变量(§4.12.4),则删除关键字   最终或更改其值不会破坏兼容性   预先存在的二进制文件通过使它们不运行,但它们不会   除非它们是,否则请查看该字段用法的任何新值   重新编译。这是真的,即使使用本身不是   编译时常量表达式(§15.28)。

     

此结果是决定支持条件的副作用   汇编,如§14.21结尾所述。

答案 1 :(得分:4)

你的常数有多接近并不重要。如果它是specfication中定义的编译时常量,则它将被内联。静态final(常量)按Java规范内联(尽管我也没有找到规范)。 This java世界文章详细讨论了该主题。相关的东西:

  

根据Java语言规范,任何使用可在编译时计算的表达式初始化的静态final字段必须编译为“内联”字段值的字节代码。也就是说,Main类中不会出现动态链接,告诉它在运行时从InterfaceA获取A的值。相反,文字1将直接编译为Main.main()。