PM *_*7-1 4 java final local-variables
我知道已经提出并回答了非常相似的问题,我阅读了我能够找到的并且仍然没有100%清楚的问题.
考虑此代码段:
public static void fooMethod {
while(<...>) {
....
final int temp = <something>;
....
}
}
Run Code Online (Sandbox Code Playgroud)
没有内部阶级,没有别的特殊或不寻常.对我来说似乎是违反直觉的.
final在上面的示例中声明局部变量是否可以用于任何目的?
我是否理解正确有或没有final这里编译器将产生完全相同的字节码?
我在这里错过了什么吗?如果是RTFM案例,请指出正确的方向.
后续问题(如果可以的话)
通过这样的重写来获得和/或失去什么(理解temp不必是原始的)?
public static void fooMethod2 {
int temp;
while(<...>) {
....
temp = <something>;
....
}
}
Run Code Online (Sandbox Code Playgroud)
在几句话:该final关键字,在局部变量和参数一起使用时,不会使其对生成的字节码(.class文件),并如市场预期,它的使用在运行时没有任何影响.(编译时,它可能会有所不同,但请查看下面的内容.)
在这些情况下,当由于匿名内部类而未强制执行时,它仅仅是一种样式选择,在记录变量的预期范围时非常有用.
以下测试证实了这些信息.
final有所不同:看看这个片段:
boolean zZ = true;
while (zZ) {
int xX = 1001; // <------------- xX
int yY = 1002; // <------------- yY
zZ = (xX == yY);
}
Run Code Online (Sandbox Code Playgroud)
两个int变量,xX和yY.第一次宣布final第二次,final从两者中取走.以下是生成的字节码(打印有javap -c):
两者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
Run Code Online (Sandbox Code Playgroud)
两者都是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
Run Code Online (Sandbox Code Playgroud)
在上面的例子中,当它们是final,编译器知道它们不相等并且从不比较它们(false无论在哪里xX == yY都在字节码中生成).
从这一点来看,我们可以得出结论,字节码方面,编译器可以在使用时对生成的代码进行一些优化final.(我不是说它们有意义,但肯定final不仅仅是这里的风格选择.)
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);
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,即使使用final,编译器不能告诉编译器时,如果xX和yY是相等的,对不对?
因此,我们可以看到:当我们生成有或没有的类时,生成的字节码完全相同(相同的MD5!).final
虽然在一般情况下,有些人说和其他人不同意使用性能优势final,在本地区块中,final绝对只是一种风格选择.
为此代码段生成的字节码...
boolean zZ = true;
int aA = 1001, bB = 1002;
while (zZ) {
int xX = aA; // <--- declaration is inside WHILE
int yY = bB;
zZ = (xX == yY);
}
Run Code Online (Sandbox Code Playgroud)
...以及此代码段的生成字节码...
boolean zZ = true;
int aA = 1001, bB = 1002;
int xX, yY; // <--- declaration is outside WHILE
while (zZ) {
xX = aA;
yY = bB;
zZ = (xX == yY);
}
Run Code Online (Sandbox Code Playgroud)
... 完全相同(当然只改变了行号).
使用对象的其他测试(不仅是原始类型变量)也表现出相同的行为.
结论是安全的,如果不在别处使用,在循环内部或外部声明局部变量几乎是一种设计选择,没有字节码效应.
注意:所有测试均在Oracle的JRE 1.7.0_13版本下进行.