前言:
最近迷上了jvm,带着好奇对其小窥一下,犹如啃鸭脖子,虽然无肉(工作中用不上,不像spring等框架那样学会了就能做项目),但是也别有一番滋味。我惊讶的发现,在java中将变量声明在循环外和循环内其实效果是一样的,反而将变量声明在循环之前还延长了该变量的作用域
示例如下:
示例1[循环内定义] |
示例2[循环外定义] |
|
public void inc(final int c) { for(int i=0; i< c; i= i++) { String s = String.valueOf(i); } int b = 0 ; int d = 0; } |
|
|
public void inc(final int c) { String s; for(int i=0; i< c; i= i++) { s = String.valueOf(i); } int b = 0 ; int d = 0; } |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
|
stack=2, locals=4, args_size=2 0: iconst_0 1: istore_2 2: goto 15 5: iload_2 //6为:String.valueOf(i); 6: invokestatic #16 9: astore_3 10: iload_2 11: iinc 2, 1 14: istore_2 15: iload_2 16: iload_1 17: if_icmplt 5 20: iconst_0 21: istore_2 22: iconst_0 23: istore_3 24: return LineNumberTable: line 5: 0 line 6: 5 line 5: 10 line 8: 20 line 9: 22 line 10: 24 LocalVariableTable: Start Length Slot Name Signature 0 25 0 this LTest1; 0 25 1 c I 2 18 2 i I 22 3 2 b I 24 1 3 d I |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
stack=2, locals=5, args_size=2 0: iconst_0 1: istore_3 2: goto 15 5: iload_3 //6为:String.valueOf(i); 6: invokestatic #16 9: astore_2 10: iload_3 11: iinc 3, 1 14: istore_3 15: iload_3 16: iload_1 17: if_icmplt 5 20: iconst_0 21: istore_3 22: iconst_0 23: istore 4 25: return LineNumberTable: line 6: 0 line 7: 5 line 6: 10 line 9: 20 line 10: 22 line 11: 25 LocalVariableTable: Start Length Slot Name Signature 0 26 0 this LTest1; 0 26 1 c I 10 5 2 s LString; 2 18 3 i I 22 4 3 b I 25 1 4 d I |
|
说明:字节码是通过javap -v xxx class文件获取的
逐行解释示例1的字节码:
0,1行表示对变量i赋0,第2个本地变量表示i;
5,6行执行String.valueOf(i)方法。
9行将String.valueOf(i)返回的值的引用赋给第3个本地变量
10,11,14将i读入栈顶,执行加1操作,然后存入第2个本地变量
15,16 分别将i, c读入栈顶
17比较栈顶两个元素,如果i<c跳转到5行。
20,21,22,23,分别是对本地的第2个变量和第3个变量赋初值。
对于示例2的第9行,表示将引用赋予本地的第二个本地变量。
总结:
从字节码的角度看,将变量定义在循环内反而效果更好,因为这样缩小了该变量的作用域,所以在今后的代码中,可以不用考虑为了优化而刻意的去将变量的定义提前到循环之前定义啦,将变量先定义后使用那是C时代的产物,那是C为了便于将代码编译成汇编的数据段和代码段而设计的。而C++,java将变量的定义当做普通的语句处理。
Posted in: java基础
Comments are closed.