分类: Java
2009-12-29 14:07:41
|
很多人的结论如下;
1)代码2比代码3的效率高;
2)代码2的可维护性不如代码3,因为变量作用域扩大了。
其实结论1)是错误的。
第2段代码反汇编及说明:
-----------------------------------------------------------------------
0: new #3; //new ArrayList()
3: dup //将新创建的ArrayList的引用复制并压入栈
4: invokespecial #4; //编译器插入的ArrayList初始化方法:ArrayList."
7: astore_1 //局部变量赋值:result2 = new ArrayList();
8: aconst_null //局部变量赋值:o = null
9: astore_2
10: iconst_0 //局部变量赋值:i = 0
11: istore_3
12: iload_3 //比较i和10
13: bipush 10
15: if_icmpge 45 //如果i >= 10 函数返回
18: new #5; //new Obj()
21: dup //将新创建的Obj的引用复制并压入栈
22: invokespecial #6; //编译器插入的Obj初始化方法 Method "
25: astore_2 //局部变量赋值:o = new Obj();
26: aload_2 //准备调用参数栈,取出局部变量的引用并压栈: o
27: iload_3 //准备调用参数栈,取出局部变量的值并压栈:i
28: invokevirtual #7; //方法调用:o.set(i);
31: aload_1 //取出局部变量的引用并压栈: result2
32: aload_2 //取出局部变量的引用并压栈: o
33: invokeinterface #8, 2; //调用List.add()方法: result2.add(o);
38: pop
39: iinc 3, 1 //i++
42: goto 12 //回到for循环头
45: return //函数返回
-----------------------------------------------------------------------
第3段代码反汇编及说明:
-----------------------------------------------------------------------
0: new #3; //new ArrayList()
3: dup /将新创建的ArrayList的引用复制并压入栈
4: invokespecial #4; //编译器插入的ArrayList初始化方法:ArrayList."
7: astore_1 /局部变量赋值:result3 = new ArrayList();
8: iconst_0 //局部变量赋值:i = 0
9: istore_2
10: iload_2 //比较i和10
11: bipush 10
13: if_icmpge 43 //如果i >= 10 函数返回
16: new #5; //new Obj()
19: dup //将新创建的Obj的引用复制并压入栈
20: invokespecial #6; //编译器插入的Obj初始化方法 Method "
23: astore_3 //局部变量赋值:o = new Obj();
24: aload_3 //准备调用参数栈,取出局部变量的引用并压栈: o
25: iload_2 //准备调用参数栈,取出局部变量的值并压栈:i
26: invokevirtual #7; //方法调用:o.set(i);
29: aload_1 //取出局部变量的引用并压栈: result3
30: aload_3 //取出局部变量的引用并压栈: o
31: invokeinterface #8, 2; //调用List.add()方法: result3.add(o);
36: pop
37: iinc 2, 1 //i++
40: goto 10 //回到for循环头
43: return //函数返回
-----------------------------------------------------------------------
小结:
1、代码2效率显然不如代码3,红色那两行是多余的。
2、代码2可维护性比较差,冯勇强前面有说明。
代码2与代码3的差异,除了多了那两句,就是局部变量的索引顺序不同,循环体的反汇编也是完全一样的。所以,代码2各方面都不如代码3,一般推荐3的写法。这与大多数人日常编码习惯是一致的:)