类文件格式的最终变量
类文件格式是否支持最终关键字,以便将其与变量一起使用?
或者它只是从代码中推断出变量的有效终结性而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₁:=4
和c₂:=5
,并且根据后续代码的位置,可以确定使用哪个常量,换句话说,它不仅仅具有“有效最终”变量,甚至可以将变量变量视为多个final
变量(在没有变量的情况下)线程同步,甚至更改堆变量可能会暂时得到类似的处理)。