两种方法差不了多少的第二种方法也没有创建很多的对象,他创建的只是句柄,对象本来都是存在了的(list初期化的时候他们就存在了),你循环里面只是创建句柄指向这些对象。句柄占用空间不是很大的。可以的话还是用第一种吧(个人看法)

解决方案 »

  1.   

    呵呵,俺与“bluesmile979(笑着)”持相反的观点。
    当然是第二种!原因有两处:
    (1) 两种做法对于垃圾收集的影响没有本质的差别,可以忽略之;
    (2) 关键的原因:临时变量的作用域问题。临时变量的作用域应该最小化;由此可以引出一个关于循环的问题,就是for循环优于while循环:
    <<
    for(Iterator it=list.iterator(); it.hasNext(); ) {
        Object each = it.next();
    }
    优于
    Iterator it=list.iterator();
    while( it.hasNext() ) {
        Object each = it.next();
    }
    >>
    在上面这两个例子中,Iterator it这个临时变量的作用域是不同的。
      

  2.   

    public class CTest{
    public static void main(String[] args){
    System.out.println("Started:");
    long time=System.currentTimeMillis();
    //Integer a;
    for(int i=0;i<100000000;i++){
    Integer a=new Integer(i);
    }
    System.out.println("accomplished:"+String.valueOf(System.currentTimeMillis()-time));
    }
    }
    运行时间前者5601ms
    后者5518ms(不同机子上和不同时间运行都有可能不同)
    两者基本上不分上下
      

  3.   

    两种方式区别不大,看看下面是两个方法的java字节码
    方法一
    public void M1();
      Code:
       0: aconst_null
       1: astore_1
       2: iconst_0
       3: istore_2
       4: goto 23
       7: aload_0
       8: getfield #2; //Field list:Ljava/util/Vector;
       11: iload_2
       12: invokevirtual #3; //Method java/util/Vector.get:(I)Ljava/lang/Object;
       15: checkcast #4; //class ClassA
       18: astore_1
       19: nop
       20: iinc 2, 1
       23: iload_2
       24: aload_0
       25: getfield #2; //Field list:Ljava/util/Vector;
       28: invokevirtual #5; //Method java/util/Vector.size:()I
       31: if_icmplt 7
       34: nop
       35: return
    方法二
    public void M2();
      Code:
       0: iconst_0
       1: istore_1
       2: goto 21
       5: aload_0
       6: getfield #2; //Field list:Ljava/util/Vector;
       9: iload_1
       10: invokevirtual #3; //Method java/util/Vector.get:(I)Ljava/lang/Object;
       13: checkcast #4; //class ClassA
       16: astore_2
       17: nop
       18: iinc 1, 1
       21: iload_1
       22: aload_0
       23: getfield #2; //Field list:Ljava/util/Vector;
       26: invokevirtual #5; //Method java/util/Vector.size:()I
       29: if_icmplt 5
       32: nop
       33: return}方法一的4-35行同方法二的2-33行基本一致,但方法一比方法二多了1-2行
       0: aconst_null
       1: astore_1
    是用来初始化ClassA a = null的,所以方法一比方法二多一个初始化a的时间
    如果少量调用这两个方法的话,区别不太大,但如果频繁调用这方法的话,还是方法二的性能稍微优越一点,
    调用两个方法循环10000次结果如下
    第一个4484
    第二个4469
      

  4.   

    呵呵,jjj3000(jjj3000) 分析得不错。
    但是这个问题其实不在执行效率的区别之上,还是和之前提到的,是局部变量的作用域的问题。
      

  5.   

    TO alienbat(死灵巫师):
    不同意。
    你为什么会认为第二种方法产生的垃圾对象会比第一种多?
    在楼主的例子中,实际上两种方法都不会有什么垃圾对象。这些对象的引用始终被List保持,不会被垃圾收集。
    其实看看第一种方法和第二种方法的区别,jjj3000(jjj3000) 反编译出来的字节码就可以展示清楚了。在循环体中除去循环控制语句不管,区别在于第一种方法执行的指令是:
    line 18:  astore_1
    而第二种方法执行的指令是:
    line 16:  atore_2
    这两条指令都是把returnAddress/引用类型存入局部变量。「所以说两种方法本质是一样的」都是执行invokevirtual #3来获取List中的对象引用。如果把楼主的例子改写成可以产生垃圾对象的例子:
    Object obj = null;
    for(int i=0; i<1000; i++) {
        obj = new Object();
    }

    for(int i=0; i<1000; i++) {
        Object obj = new Object();
    }
    这两种方法,产生的垃圾对象也是可以等价的。每次循环一次,上一次循环的对象就失去了引用,变成了垃圾对象。
    〔呵呵,第二种方法还会多出一个垃圾对象。循环结束后,最后一次循环产生的新对象在第一种方法中还会被obj保持。〕
    :)
      

  6.   

    看了xiaohaiz(老土进城,两眼通红)的分析
    想起了list有过期引用的特例,就象stack一样
    垃圾收集器是不会对这里面的对象进行回收的
    list将自己管理这些对象
    最还在代码最后加上
    a=null;
      

  7.   

    两种方法差不多
    由于对象是在list产生时已经创建
    你用a=list.get(i);只是创建了一个指向list.get(i)的一个索引
    方法一只是声明一次然后不停的改变其指向的对象
    方法二每次声明一次,上一次声明的将在适当的时候被收回
      

  8.   

    TO fantasyCoder(牛仔+T恤):
    看你开始思路还算清楚,怎么最后来了一个画蛇添足,加上“a=null”做什么。:)
      

  9.   

    to  fantasyCoder(牛仔+T恤)
    何时启动垃圾收集器是没有办法控制的。即使你使用System.gc(),也仅仅是建议垃圾收集,而不是强迫垃圾收集。
      

  10.   

    承认错误,同意 xiaohaiz(老土进城,两眼通红)的看法。