Déclarer une variable final
ou ne pas la déclarer final
, mais la garder effectivement finale peut entraîner (dépend du compilateur) un bytecode différent.
Jetons un coup d'œil sur un petit exemple:
public static void main(String[] args) {
final boolean i = true; // 6 // final by declaration
boolean j = true; // 7 // effectively final
if (i) { // 9
System.out.println(i);// 10
}
if (!i) { // 12
System.out.println(i);// 13
}
if (j) { // 15
System.out.println(j);// 16
}
if (!j) { // 18
System.out.println(j);// 19
}
}
Le bytecode correspondant de la main
méthode (Java 8u161 sur Windows 64 Bit):
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_1
2: iconst_1
3: istore_2
4: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
7: iconst_1
8: invokevirtual #22 // Method java/io/PrintStream.println:(Z)V
11: iload_2
12: ifeq 22
15: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
18: iload_2
19: invokevirtual #22 // Method java/io/PrintStream.println:(Z)V
22: iload_2
23: ifne 33
26: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
29: iload_2
30: invokevirtual #22 // Method java/io/PrintStream.println:(Z)V
33: return
La table des numéros de ligne correspondante:
LineNumberTable:
line 6: 0
line 7: 2
line 10: 4
line 15: 11
line 16: 15
line 18: 22
line 19: 26
line 21: 33
Comme on le voit le code source au niveau des lignes 12
, 13
, 14
ne figure pas dans le code d'octets. C'est parce que i
c'est true
et ne changera pas son état. Ainsi, ce code est inaccessible (plus dans cette réponse ). Pour la même raison, le code à la ligne 9
manque également. Il i
n'est pas nécessaire d'évaluer l'état de car il est true
certain.
D'un autre côté, bien que la variable j
soit effectivement finale, elle n'est pas traitée de la même manière. Il n'y a pas de telles optimisations appliquées. L'état de j
est évalué deux fois. Le bytecode est le même, même s'il j
est effectivement définitif .