上周论坛有个帖子讨论有关for的写法,说是有个代码评审批评了下属的代码写法问题,具体见链接:
http://www.iteye.com/topic/722599
大家的一致意见是楼主写法没有问题,"问题是数组长度的的写法,应该先用变量保存,循环里不要直接计算",这里我感到怀疑。
我也回复了该贴,说是看下for的"源码",这里的意思是for的执行过程,有同学问我怎么看,这里做下分析,
过程很简单,就是用javap 命令来反编译.class文件即可,下面我们从数组构建开始,一个一个的分析.
1:javap -c 命令分析数组的构建
public class E{
public static void main(String...args){
int[] arr={1,2,3};
int[] arr2={1,2,3};
}
}
分析结果如下:
0:iconst_3 //常数3装载到操作数栈:需要初始化数组的长度
1:newarray int //堆中new一个新的int类型的数组
3:dup //直接操纵操作数栈,打开操作
4:iconst_0 //常数0装载到操作数栈:数组下标
5:iconst_1 //常数1装载到操作数栈:对应的值
6:iastore //把一个值从操作数栈存入到数组成分:arr[0]=1
7:dup //...
8:iconst_1 //...
9:iconst_2 //...
10:iastore //...arr[1]=2
11:dup //...
12:iconst_2 //...
13:iconst_3 //...
14:iastore //...arr[2]=3
15:astore_1 //...为局部变量存入第一个值,该值为以上在操作数栈构造完成的数组类型16:iconst_3 //---------开始构造第二个数组
17:newarray int //
19:dup //
20:iconst_0 //
21:iconst_1 //
22:iastore //
23:dup //
24:iconst_1 //
25:iconst_2 //
26:iastore //
27:dup //
28:iconst_2 //
29:iconst_3 //
30:iastore //
31:astore_2 //----------存入第二个数组完成
33:return //结束返回
2:javap -c 命令分析循环的构建
public class D{
public static void main(String...args){
for(int j=0;j<2;){
}
}
}
分析结果如下:
0:iconst_0 //常数0装载到操作数栈
1:istore_1 //存入第一个值到局部变量:j=0的赋值操作
2:iload_1 //调出第一个局部变量到操作数栈:取出j的值
3:iconst_2 //常数2装载到操作数栈
4:if_icmpge 10 //判断大小:j<2,若不成立直接跳转到10行
7:goto 2 //跳转到2行继续执行
10:return //结束返回
3:有了以上基础知识,我们来分析http://www.iteye.com/topic/722599中的两种模式的循环结构
3.1:javap -c 分析String类型的数组循环的构建
...吃饭去,回来接着写
继续:变量声明在外部的情况
public class D{
public static void main(String...args){
String[] arr={"1","2","3"};
String i=null;
for(int j=0;j<arr.length;j++){
i=arr[j];
}
}
}
分析结果如下:
0:iconst_3
1:anewarray #2;//class java/lang/String
4:dup
5:iconst_0
6:ldc #3;//String 1 //将字符串1的引用push到操作数栈
8:aastore //将一个值(数组类型)从栈存入到数组成分
9:dup
10:iconst_1
11:ldc #4;//String 2
13:aastore
14:dup
15:iconst_2
16:ldc #5;//String 3
18:aastore
19:astore_1 //存入第一个值到局变(数组类型)chushihua
20:aconst_null //申明数组类型常量为null
21:astore_2 //存入第二个值到局变(数组类型)初始化i完成
22:iconst_0 //装载常数0到操作数栈(整形)
23:istore_3 //从栈存入第三个值到局变(整形)
24:iload_3 //将第三个局变调入栈(整形)
25:aload_1 //将第一个局变调入栈(数组类型)
26:arraylength //计算数组长度
27:if_icmpge 40 //比较大小
30:aload_1 //将第一个局变调入栈(数组类型)
31:iload_3 //将第三个局变调入栈(整形)
32:aaload //将一个数组成分装载到操作数栈(该数组的成员类型为数组类型)
33:astore_2 //从栈把第二个值存入到局变(数组型),覆盖之前第21行的存入局变的值
34:iinc 3,1 //第三个局变自增1(整型)
37:goto 24 //转向第24步
40:return //结束返回
3.2变量声明在内部的情况
public class D{
public static void main(String...args){
String[] arr={"1","2","3"};
for(int j=0;j<arr.length;j++){
String i=arr[j];
}
}
}
分析结果如下:
0:iconst_3
1:anewarray #2;//class java/lang/String
4:dup
5:iconst_0
6:ldc #3;//String 1
8:aastore
9:dup
10;iconst_1
11:ldc #4;//String 2
13:aastore
14:dup
15:iconst_2
16:ldc #5;//String 3
18:aastore
19:astore_1 //初始化arr完成
20:iconst_0
21:istore_2
22:iload_2
23:aload_1
24:arraylength
25:if_icmpge 38
28:aload_1
29:iload_2
30:aaload
31:astore_3 //从栈存入第三个值到局变(数组类型),在下次循环的时候会被覆盖
32:iinc 2,1
35:goto 22
38:return
从上面两个例子可以得出两种写法的差别,至于那个评审所说的浪费空间?????????
结束.