类文件格式的最终​​变量

文件格式是否支持最终关键字,以便将其与变量一起使用?
或者它只是从代码中推断出变量的有效终结性而JIT编译器基于它执行优化?

这里 ,在类文件格式文档中,他们提到了关于final关键字,但仅限于将其与final块final类一起使用的情况。
最终变量没有任何内容。

不,在类文件中没有编码这样的信息。

您可以通过使用final局部变量编译源文件并且没有final来轻松validation这一点 – 结果类将是相同的。

但是,Java 8添加了MethodParameters属性,该属性记录有关方法参数的名称和访问标志的信息。 这意味着,您可以检查方法参数是否为final

即时编译器不需要了解final本地化 – 他们可以轻松确定任何表达式的实际范围。 即使变量不是最终的,例如

  int x = 1; // ... code A ... x = 2; // ... code B ... 

编译器将优化代码A ,就像x始终为1 ,代码B就像x始终为2

也许我们应该首先重新考虑“ 变量 ”一词。 在大多数情况下,术语“变量”包括局部变量, static和非static字段以及甚至通常甚至是数组元素(例如,在存储器模型中)。 由于数组元素不支持final ,因此只能为字段和局部变量给出答案。

对于字段,有ACC_FINAL标志,用于ACC_FINAL字段是否为final 。 它有不同的后果。 static final字段只能在类初始值设定项中写入,而final实例字段不仅可以在构造函数中写入,还可以通过具有访问覆盖的reflection来写入。 试图在优化时从实例字段的final性质中获益的JVM必须注意检测reflection修改。

对于局部变量,没有final标志,事实上,根本没有正式的声明。 在Java字节代码中,局部变量只是堆栈帧中的索引,可以随意重用而不需要预知。 因此,对局部变量索引的写入可以是变量的变化,也可以是新变量的相同索引的重用,例如{ int x=4; } { int y=5; } { int x=4; } { int y=5; } 可能会被编译为与{ int x=4; x=5; }相同的字节代码 { int x=4; x=5; } { int x=4; x=5; }

对于JVM的优化器,无论如何都没关系,因为它会将局部变量的操作转换为SSAforms ,因此,在上面的例子中,优化器会将代码视为必须为常量, c₁:=4c₂:=5 ,并且根据后续代码的位置,可以确定使用哪个常量,换句话说,它不仅仅具有“有效最终”变量,甚至可以将变量变量视为多个final变量(在没有变量的情况下)线程同步,甚至更改堆变量可能会暂时得到类似的处理)。