【问题标题】:What is inlineable as a run-time constant?什么是可内联的作为运行时常量?
【发布时间】:2014-05-27 16:36:33
【问题描述】:

必须是 private + static + final 才能作为编译时常量内联吗?

什么可以作为运行时常量内联?

还有呢:

private final ...
static final ...
final ...

【问题讨论】:

    标签: java access-modifiers


    【解决方案1】:

    JLS 4.12.4 指定什么是“常量变量”。基本上要求是必须是final,类型是原始类型或者String,值必须是常量表达式(15.28)。

    常量变量的值将被字节码编译器内联。

    JLS 规则不区分 static 与否,也不区分不同的访问修饰符。


    但是public static final可以通过反射来改变,那么它是compile-time final吗?

    是的。事实上,对常量变量的反射性更改没有任何影响:

    “即便如此,仍有许多复杂情况。如果在字段声明中将 final 字段初始化为常量表达式(第 15.28 节),则可能不会观察到对 final 字段的更改,因为使用它final 字段在编译时被常量表达式的值替换。" - JLS 17.5.3


    什么可以作为运行时常量内联?

    有趣的问题。我没有看到 JLS 中直接提到过这个问题。但是,显然可以对此进行反思(鉴于 JLS 17.5.3 所说的)。

    允许内联的一种情况(如果 JIT 编译器可以处理它)是一个局部变量,它要么是最终的,要么是有效的最终变量,并且具有 JIT 编译器可以推导出的初始值设定项始终相同。总体约束是运行时内联不能改变程序的可观察行为。 (这里我们不需要考虑反射,因为局部变量不能通过反射访问或改变。)

    【讨论】:

      【解决方案2】:

      访问修饰符对内联没有影响。

      重要的是该值来自一个常量表达式 (http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.28) 并且它是合适的类型(原始或字符串)。

      虽然可以通过多种方式更改最终赋值(最简单的方法是使用新值重新编译包含类),但如果遵守上述限制,它们仍然被视为常量。所以即使是 public final static 也可以(并且经常)编译时内联。

      【讨论】:

        【解决方案3】:

        根据您的需要,常量可以是私有的或公共的,但您应该使用 static + final。

        所以...

        private static final
        

        或者……

        public static final
        

        【讨论】:

        • 我改变了问题,对不起。但是public static final可以通过反射来改变,那么它是compile-time final吗?
        【解决方案4】:

        任何标记为 static final 的字段都不能在运行时更改*,即使使用反射也是如此,并且将被内联。

        *需要注意的是,我相信您可以通过 unsafe 操作来做到这一点。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-05-04
          • 2012-07-17
          • 2011-02-22
          • 1970-01-01
          • 2014-05-20
          • 2014-11-06
          相关资源
          最近更新 更多