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

时间:2015-05-10 12:18:08

标签: java jvm final jvm-bytecode

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

代码

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

字节码

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

是否有任何特定原因保留本地变量的访问标志,而不是保存磁盘空间?因为对我而言,final似乎是变量的一个相对非平凡的属性。

1 个答案:

答案 0 :(得分: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;
}

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

// 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