RandomAccess接口的使用

引子: RandomAccess在类Collections的shuffle()方法中的使用:(jdk源码如下)
Java代码   收藏代码
  1. <span style="font-size: small;">/** 
  2.      * Randomly permute the specified list using the specified source of 
  3.      * randomness.  All permutations occur with equal likelihood 
  4.      * assuming that the source of randomness is fair.<p> 
  5.      * 
  6.      * This implementation traverses the list backwards, from the last element 
  7.      * up to the second, repeatedly swapping a randomly selected element into 
  8.      * the "current position".  Elements are randomly selected from the 
  9.      * portion of the list that runs from the first element to the current 
  10.      * position, inclusive.<p> 
  11.      * 
  12.      * This method runs in linear time.  If the specified list does not 
  13.      * implement the {@link RandomAccess} interface and is large, this 
  14.      * implementation dumps the specified list into an array before shuffling 
  15.      * it, and dumps the shuffled array back into the list.  This avoids the 
  16.      * quadratic behavior that would result from shuffling a "sequential 
  17.      * access" list in place. 
  18.      * 
  19.      * @param  list the list to be shuffled. 
  20.      * @param  rnd the source of randomness to use to shuffle the list. 
  21.      * @throws UnsupportedOperationException if the specified list or its 
  22.      *         list-iterator does not support the <tt>set</tt> operation. 
  23.      */  
  24.   
  25.   
  26. public static void shuffle(List<?> list, Random rnd) {  
  27.         int size = list.size();  
  28.         if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {//注意这一句中的instanceof  
  29.             for (int i=size; i>1; i--)  
  30.                 swap(list, i-1, rnd.nextInt(i));  
  31.         } else {  
  32.             Object arr[] = list.toArray();  
  33.   
  34.             // Shuffle array  
  35.             for (int i=size; i>1; i--)  
  36.                 swap(arr, i-1, rnd.nextInt(i));  
  37.   
  38.             // Dump array back into list  
  39.             ListIterator it = list.listIterator();  
  40.             for (int i=0; i<arr.length; i++) {  
  41.                 it.next();  
  42.                 it.set(arr[i]);  
  43.             }  
  44.         }  
  45.     }</span>  

 由以上的jdk源码可见,在对实现list接口的对象进行洗牌,打乱时,区分了该类是否是RandomAccess的实例,这样做有什么意义呢?请继续向下看:


介绍: 

在jdk文档中对RandomAccess接口的定义如下:
public interface RandomAccess

List 实现所使用的标记接口,用来表明其支持快速(通常是固定时间)随机访问。此接口的主要目的是允许一般的算法更改其行为,从而在将其应用到随机或连续访问列表时能提供良好的性能。


将操作随机访问列表的最佳算法(如 ArrayList )应用到连续访问列表(如 LinkedList )时,可产生二次项的行为。如果将某个算法应用到连续访问列表,那么在应用可能提供较差性能的算法前,鼓励使用一般的列表算法检查给定列表是否为此接口的一个 instanceof ,如果需要保证可接受的性能,还可以更改其行为。

现在已经认识到,随机和连续访问之间的区别通常是模糊的。例如,如果列表很大时,某些 List 实现提供渐进的线性访问时间,但实际上是固定的访问时间。这样的 List 实现通常应该实现此接口。


强调:

JDK中推荐的是对List集合尽量要实现RandomAccess接口

如果集合类是RandomAccess的实现,则尽量用for(int i = 0; i < size; i++) 来遍历而不要用Iterator迭代器来遍历,在效率上要差一些。反过来,如果List是Sequence List,则最好用迭代器来进行迭代。


JDK中说的很清楚,在对List特别是Huge size的List的遍历算法中,要尽量来判断是属于RandomAccess(如ArrayList)还是Sequence List (如LinkedList),因为适合RandomAccess List的遍历算法,用在Sequence List上就差别很大,常用的作法就是:
    要作一个判断:
    if (list instance of RandomAccess) {
        for(int m = 0; m < list.size(); m++){}
    }else{
        Iterator iter = list.iterator();
        while(iter.hasNext()){}
    }


验证:

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;


class TestCls {
  private int i;
  
  public TestCls(int i) {
    this.i = i;
  }

  public int getI() {
    return i;
  }

  public void setI(int i) {
    this.i = i;
  }
}

public class TestMain {
  public static void initList(List<TestCls> list, int n) {
    for (int i = 0; i < n; i++) {
      list.add(new TestCls(i));
    }
  }
  // 使用循环进行对列表的迭代

  public static void traverseWithLoop(List<TestCls> list) {
    long starttime = 0;
    long endtime = 0;
    starttime = System.currentTimeMillis();

    for (int i = 0; i < list.size(); i++) {
      // 业务逻辑
      TestCls testCls = list.get(i);
      testCls.getI();
    }

    endtime = System.currentTimeMillis();
    System.out.println("使用i++的loop一共花了" + (endtime - starttime) + "ms时间");

  }

  public static void traverseWithIterator(List<TestCls> list) {
    long starttime = 0;
    long endtime = 0;
    starttime = System.currentTimeMillis();

    for (TestCls TestCls : list) {
      TestCls.getI();
    }

    endtime = System.currentTimeMillis();
    System.out.println("使用增强For循环一共花了" + (endtime - starttime) + "ms时间");
  }

  public static void main(String[] args) {
    ArrayList<TestCls> arraylist = new ArrayList<>();
    LinkedList<TestCls> linkedlist = new LinkedList<>();
    initList(arraylist, 100000);
    initList(linkedlist, 100000);
    System.out.println("ArrayList 开始使用增强For循环");
    traverseWithIterator(arraylist);
    System.out.println("");
    
    System.out.println("ArrayList 开始使用Loop循环");
    traverseWithLoop(arraylist);
    System.out.println("");
    
    System.out.println("LinkedList 开始使用增强For循环");
    traverseWithIterator(linkedlist);
    System.out.println("");
    
    System.out.println("LinkedList 开始使用Loop循环");
    traverseWithLoop(linkedlist);
  }
}


运行程序输出的结果为:

ArrayList 开始使用增强For循环
使用增强For循环一共花了9ms时间

ArrayList 开始使用Loop循环
使用i++的loop一共花了7ms时间

LinkedList 开始使用增强For循环
使用增强For循环一共花了12ms时间

LinkedList 开始使用Loop循环
使用i++的loop一共花了4710ms时间


结论:

根据程序输出的结果的确证明了,ArrayList使用增强For循环和Loop效率差别并不大,而linkedList使用Iterator进行迭代效率更高.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值