2015-05-10 2 views
6

Analysieren der Bytecode dieser einfachen Klasse, bin ich zu dem Schluss gekommen, dass der Compiler keine Informationen über eine lokale Variable final behält. Dies scheint jedoch seltsam, da ich glaube, dass der HotSpot-Compiler diese Informationen tatsächlich dazu verwenden kann, Optimierungen vorzunehmen.Variabler "endgültiger" Modifikator in Bytecode verloren?

-Code:

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

Bytecode:

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 

Gibt es einen bestimmten Grund nicht die Zugriffs-Flags einer lokalen Variablen, die nicht zu halten Speicherplatz sparen? Weil es für mich scheint, dass final eine relativ nicht-triviale Eigenschaft einer Variablen ist.

+4

Hotspot JITs verwandeln den Bytecode in eine SSA Darstellung intern, die AIUI finalness redundante ohnehin macht. Und es gibt andere Fiktionen in Java-Land, die auf Bytecodeebene nicht real sind, z. Generika – the8472

+0

Es macht Sinn für Generika, da sie Abwärtskompatibilität gebrochen hätten, aber "final" war von Anfang an dabei. – Clashsoft

+0

checked Ausnahmen wäre ein anderes Beispiel. – the8472

Antwort

7

Der Modifizierer final ist im Bytecode nicht vorhanden, aber der Compiler verwendet diese Informationen bereits, um eine Optimierung vorzunehmen. Obwohl Ihr Beispiel es nicht zeigt, kann der Compiler den Wert der final-Variable in der Bytecode-Darstellung der Methode einreihen, was zu einer besseren Leistung führt. So etwas wie die unten kann den Unterschied zeigen:

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; 
} 

Die erzeugte Bytecode jeweils für jede Methode:

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