请您先登录,才能继续操作
精华帖 (3) :: 良好帖 (1) :: 新手帖 (15) :: 隐藏帖 (2)
|
|
---|---|
作者 | 正文 |
发表时间:2010-08-03
最后修改:2010-08-03
上周论坛有个帖子讨论有关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
从上面两个例子可以得出两种写法的差别,至于那个评审所说的浪费空间?????????
结束.
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-08-03
最后修改:2010-08-04
可以看出,arr.length执行的是一条指令arraylength
|
|
返回顶楼 | |
发表时间:2010-08-03
向楼主学习 在真理面前一切评审都是纸老虎
|
|
返回顶楼 | |
发表时间:2010-08-03
大家的学习热情很是佩服,不过个人真的觉得花这么多时间研究一个for循环实在是有点。。。
|
|
返回顶楼 | |
发表时间:2010-08-03
真理只在少数人手上,就是那些偏执狂
|
|
返回顶楼 | |
发表时间:2010-08-03
楼主也太狠了,这反编译都分析的这么清楚!
|
|
返回顶楼 | |
发表时间:2010-08-03
唉,lz为什么不直接把结论给大家呢,我只想知道通过你的分析,以后这个for循环要如何写更合适,呵呵.那么长的分析我想大部分人都是懒得去看的!
|
|
返回顶楼 | |
发表时间:2010-08-04
不错,知其然,还要知其所以然
|
|
返回顶楼 | |
发表时间:2010-08-04
不如直接上cpu assembly分析了,离事实更近一步。
|
|
返回顶楼 | |
发表时间:2010-08-04
分析看不懂,没看,只想看结果
|
|
返回顶楼 | |