2015-05-10 15 views
6

Analizzando il bytecode di questa classe semplice, sono giunto alla conclusione che il compilatore non conserva alcuna informazione su una variabile locale che è final. Ciò sembra strano, dal momento che ritengo che il compilatore HotSpot possa effettivamente utilizzare queste informazioni per fare ottimizzazioni.Modificatore 'finale' variabile perso in Bytecode?

Codice:

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 

v'è alcuna ragione specifica non mantenere le bandiere di accesso di una variabile locale, diversa risparmiare spazio sul disco? Perché per me, sembra che essere final sia una proprietà relativamente non banale di una variabile.

+4

SIC hotspot trasformano il bytecode in una rappresentazione SSA internamente, che AIUI rende superfluo finalness comunque. E ci sono altre finzioni in java-land che non sono reali a livello di bytecode, ad es. generici – the8472

+0

Ha senso per i generici, dal momento che avrebbero rotto la compatibilità verso il basso, ma 'finale' è stato lì fin dall'inizio. – Clashsoft

+0

le eccezioni controllate sarebbero un altro esempio. – the8472

risposta

7

Il modificatore final non è presente nel bytecode ma il compilatore utilizza già queste informazioni per ottimizzare. Sebbene il tuo esempio non lo mostri, il compilatore può incorporare il valore della variabile final nella rappresentazione bytecode del metodo, portando a prestazioni migliori. Qualcosa di simile al di sotto può mostrare la differenza:

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

Il bytecode generato sono rispettivamente per ogni metodo:

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