今天在C#里面看到:
之前一直认为
for (int i = 0, h = arr.Count; i < h; i++)
和
for (int i = 0; i < arr.Count; i++)
两种写法,在C#里应该是差不多的,今天突然有人问,就写了个程序测试了一下,结果出乎我的意料
如果arr是List<T>,前者的效率比后者高大约一倍,如果arr是string[],两者效率基本差不多
原帖子地址:http://topic.csdn.net/u/20120706/16/CEB33682-FF71-402C-9FE9-580F5ECFDFC1.html
我写的代码测试:int tnum = 1000000; // 添加或查找的次数
int outnum = 10; // 外层循环次数
ArrayList<String> arr = new ArrayList<String>();
for (int i = 0; i < tnum; i++) {
arr.add(Integer.toString(i));
}
String[] arr2 = new String[tnum];
for(int j=0;j<outnum;j++)
{
Long time = System.currentTimeMillis();
String msg;
msg = "Number ";
for (int i = 0, h = arr.size(); i < h; i++)
{
}
time = System.currentTimeMillis()-time;
System.out.println(msg+"耗时:"+time);
msg = ".Count ";
time = System.currentTimeMillis();
for (int i = 0; i < arr.size(); i++)
{
}
time = System.currentTimeMillis()-time;
System.out.println(msg+"耗时:"+time);
msg = "Length ";
time = System.currentTimeMillis();
for (int i = 0; i < arr2.length; i++)
{
}
time = System.currentTimeMillis()-time;
System.out.println(msg+"耗时:"+time);
}
我发现时间都差不多啊,难道是因为ArrayList的原因?还是JAVA这个用的时间本来就是一样的?
============================================================================
LZ这样比较是很难看出来的,还是查看伪代码指令比较好理解
1
2
3
4
5
6
7
8
|
import
java.util.*;
public
class
jp {
public
static
void
main(String[] args)
throws
Throwable {
List<String> list =
new
ArrayList<String>();
for
(
int
i=
0
, j=list.size(); i<j; i++);
//list.size()只调用一次
for
(
int
i=
0
; i<list.size(); i++);
//list.size()每次都调用
}
}
|
javac jp.java //编译
javap -c jp //查看伪代码指令
E:\Test>javap -c jp
Compiled from "jp.java"
public class jp {
public jp();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":
()V
4: return
public static void main(java.lang.String[]) throws java.lang.Throwable;
Code:
0: new #2 // class java/util/ArrayList
3: dup
4: invokespecial #3 // Method java/util/ArrayList."<init
>":()V
7: astore_1
8: iconst_0
9: istore_2
10: aload_1
11: invokeinterface #4, 1 // InterfaceMethod java/util/List.si
ze:()I
16: istore_3
17: iload_2
18: iload_3
19: if_icmpge 28
22: iinc 2, 1
25: goto 17
28: iconst_0
29: istore_2
30: iload_2
31: aload_1
32: invokeinterface #4, 1 // InterfaceMethod java/util/List.si
ze:()I
37: if_icmpge 46
40: iinc 2, 1
43: goto 30
46: return
}
红色部分是第一种循环情况
8: iconst_0把0入栈
9: isrote_2把0出栈并赋给2号索引变量i,即i=0操作,1号索引变量是list,即前面的astore_1把ArrayList对象赋给1号索引变量
10: aload_1把1号索引变量入栈,即list入栈
11: invokeinterface把list出栈并调用其size方法,把结果入栈
16: istore_3把size方法的结果出栈并赋给3号索引变量j,即j=list.size()操作
17: iload_2
18: iload_3 把2,3号索引变量入栈
19: if_icmpge 28 比较入栈的两个数据,前者大于等于后者则跳转到28行指令,即不满足i<j跳转
22: iinc 2, 1 2号索引变量i自增1
25: goto 17 跳转到17行指令,即for重新开始循环
蓝色部分是第二种情况(循环体)
28:iconst_0 0入栈
29:istore_2 0出栈并赋给i
30:iload_2 i入栈
31:aload_1 list入栈
32:invokeinterface list出栈并调用size方法,把结果入栈
37: if_icmpge 46 比较入栈的两个数据,前者大于等于后者则跳转到46行指令,即不满足i<list.size
40: iinc 2, 1 2号索引变量i自增1
43: goto 30 跳转到30行指令,即for重新开始循环
比较可以看出,第一种情况,list.size只需要执行一次,第二种则每次循环都要执行