有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

类文件格式的java最终变量

class文件格式是否提供了对final关键字的支持,以防与变量一起使用
或者它只是从代码中推断出变量的有效终结性,JIT编译器会基于此执行优化

Here,在类文件格式文档中,他们提到了final关键字,但仅在将其与final blockfinal class一起使用时才提到
没有关于最终变量的任何内容


共 (2) 个答案

  1. # 1 楼答案

    不,类文件中没有编码此类信息

    您可以通过编译一个带有final局部变量而不带final的源文件来轻松验证这一点-结果类将是相同的

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

    即时编译器不需要知道final局部变量-它们可以轻松确定任何表达式的实际范围。即使变量不是最终变量,例如

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

    编译器将优化代码A,就像x总是1,而代码B就像x总是2

  2. # 2 楼答案

    也许我们应该首先重新考虑术语“变量”。在大多数上下文中,术语“变量”包括局部变量、static和非static字段,并且通常甚至包括数组元素(例如,在内存模型中)。由于数组元素不支持final,因此只能对字段和局部变量给出答案

    对于字段,^{}标志,它告诉字段是否为final。它有不同的后果static final字段只能在类初始值设定项中写入,而final实例字段不仅可以在构造函数中写入,还可以通过带有访问重写的反射写入。JVM在优化时试图从实例字段的final特性中获益,必须注意检测反射修改

    对于局部变量,没有final标志,事实上,甚至根本没有正式的声明。在Java字节码中,局部变量只是stack frame中的索引,可以在没有预兆的情况下随意重用。因此,对局部变量索引的写入可以是变量的更改,也可以是对新变量重复使用相同的索引,例如{ int x=4; } { int y=5; }可能被编译为与{ int x=4; x=5; }相同的字节码

    对于JVM的优化器来说,这并不重要,因为它会将局部变量上的操作转换为SSA form,因此,在上面的示例中,优化器会将代码视为必须使用常量c₁:=4c₂:=5,并且根据后续代码的位置,可以确定使用哪个常量,换句话说,它不仅仅是拥有“有效的最终”变量,甚至更改的变量也可以像处理多个final变量一样处理(在没有线程同步的情况下,即使更改堆变量也可能暂时得到类似的处理)