变量'final'修饰符在字节码中丢失了?

Cla*_*oft 7 java jvm final jvm-bytecode

分析这个简单类的字节码,我得出的结论是编译器不保留有关局部变量的任何信息final.这看起来很奇怪,因为我相信HotSpot编译器实际上可以使用这些信息来进行优化.

代码:

public static void main(String[] args)
{
    final int i = 10;
    System.out.println(i);
}
Run Code Online (Sandbox Code Playgroud)

字节码:

public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
  stack=2, locals=2, args_size=1
     0: bipush        10
     2: istore_1      
     3: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
     6: bipush        10
     8: invokevirtual #22                 // Method java/io/PrintStream.println:(I)V
    11: return        
  LineNumberTable:
    line 7: 0
    line 8: 3
    line 9: 11
  LocalVariableTable:
    Start  Length  Slot  Name   Signature
        0      12     0  args   [Ljava/lang/String;
        3       9     1     i   I
Run Code Online (Sandbox Code Playgroud)

除了节省磁盘空间之外,是否有任何特定原因保留本地变量的访问标志?因为对我来说,似乎存在final变量的相对非平凡的属性.

man*_*uti 8

final修改是不存在的,但字节码编译器已经使用这些信息来做出一些优化.虽然您的示例未显示它,但编译器可能会final在方法的字节码表示中内联变量的值,从而获得更好的性能.像下面这样的东西可以显示出差异:

public int addFinal() {
    final int i = 10;
    final int j = 10;
    return i + j;
}

public int addNonFinal() {
    int i = 10;
    int j = 10;
    return i + j;
}
Run Code Online (Sandbox Code Playgroud)

生成的字节码分别用于每种方法:

// addFinal
bipush 10
istore_1
bipush 10
istore_2
bipush 20
ireturn


// addNonFinal
bipush 10
istore_1
bipush 10
istore_2
iload_1
iload_2
iadd
ireturn
Run Code Online (Sandbox Code Playgroud)