In a few words: The final
keyword, when used in local variables and parameters, does not make it to the generated bytecode (.class
file) and, as expected, its use has no effect during runtime. (Compile-time, it could make a diference, though, check below.)
在这些情况下,当由于匿名内部类而未强制执行时,它只是一个style选择,有助于记录变量的预期范围。
以下测试证实了该信息。
1:如果编译器可以利用它,使用final
有所不同:
看看这个片段:
boolean zZ = true;
while (zZ) {
int xX = 1001; // <------------- xX
int yY = 1002; // <------------- yY
zZ = (xX == yY);
}
Two int
变量,xX
and yY
。首次将两者声明为final
第二次,拿走了final
来自两者。这是生成的字节码(打印为javap -c
):
Both final
:
0: iconst_1 // pushes int 1 (true) onto the stack
1: istore_1 // stores the int on top of the stack into var zZ
2: goto 15
5: sipush 1001 // pushes 1001 onto the operand stack
8: istore_2 // stores on xX
9: sipush 1002 // pushes 1002 onto the operand stack
12: istore_3 // stores on yY
13: iconst_0 // pushes 0 (false): does not compare!! <---------
14: istore_1 // stores on zZ
15: iload_1 // loads zZ
16: ifne 5 // goes to 5 if top int (zZ) is not 0
19: return
两者都非final
:
// 0: to 12: all the same
13: iload_2 // pushes xX onto the stack
14: iload_3 // pushes yY onto the stack
15: if_icmpne 22 // here it compares xX and yY! <------------
18: iconst_1
19: goto 23
22: iconst_0
23: istore_1
24: iload_1
25: ifne 5
28: return
在上述情况下,当他们final
, 编译器知道它们不相等并且从不比较它们 (false
在字节码中的任意位置生成xX == yY
is).
由此,我们可以得出结论,就字节码而言,编译器does can使用时对生成的代码进行一些优化final
。 (我并不是说它们有意义,但可以肯定final
不仅是一个style选择这里。)
2:如果编译器无法得出任何结论,请使用final
在本地变量上只是一个设计选择:
现在采用以下代码:
boolean zZ = true;
int aA = 1001;
int bB = 1002;
while (zZ) {
final int xX = aA; // <------- took away the "final" here, didnt matter
final int yY = bB; // <------- took away the "final" here, didnt matter
zZ = (xX == yY);
}
在这种情况下,即使使用final
,编译器无法告诉编译时如果xX
and yY
是平等的,对吗?
正因为如此,我们可以看到:生成的字节码是完全一样的(相同的MD5!)当我们生成类时有还是没有final
.
同时,在一般情况, some say http://javarevisited.blogspot.com/2011/12/final-variable-method-class-java.html#ixzz2UMSuuswH and 其他人不同意 http://www.ibm.com/developerworks/java/library/j-jtp04223/index.html使用有性能优势final
, 在当地街区,final
绝对只是一个style choice.
3:循环内部或外部的局部变量 - 完全没有区别:
该片段生成的字节码...
boolean zZ = true;
int aA = 1001, bB = 1002;
while (zZ) {
int xX = aA; // <--- declaration is inside WHILE
int yY = bB;
zZ = (xX == yY);
}
...以及该片段生成的字节码...
boolean zZ = true;
int aA = 1001, bB = 1002;
int xX, yY; // <--- declaration is outside WHILE
while (zZ) {
xX = aA;
yY = bB;
zZ = (xX == yY);
}
...are 一模一样(当然,只有行号发生了变化)。
使用对象(不仅仅是原始类型变量)的其他测试显示了相同的行为。
可以肯定地得出结论,如果不在其他地方使用,在循环内部或外部声明局部变量几乎是一个设计选择,没有字节码效果。
Note: All tests were made under Oracle's JRE, version 1.7.0_13.