关于JAVA for循环效率的问题

今天在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这样比较是很难看出来的,还是查看伪代码指令比较好理解

Java code ?
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只需要执行一次,第二种则每次循环都要执行

猜你喜欢

转载自coolwhy1.iteye.com/blog/1884998