RandomAccess接口的使用

RandomAccess在类Collections的shuffle()方法中的使用:(jdk源码如下)

 1 /**
 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     public static void shuffle(List<?> list, Random rnd) {
25         int size = list.size();
26         if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
27             for (int i=size; i>1; i--)
28                 swap(list, i-1, rnd.nextInt(i));
29         } else {
30             Object arr[] = list.toArray();
31 
32             // Shuffle array
33             for (int i=size; i>1; i--)
34                 swap(arr, i-1, rnd.nextInt(i));
35 
36             // Dump array back into list
37             ListIterator it = list.listIterator();
38             for (int i=0; i<arr.length; i++) {
39                 it.next();
40                 it.set(arr[i]);
41             }
42         }
43     }
类Collections的shuffle()方法

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

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


/**
 * Marker interface used by <tt>List</tt> implementations to indicate that
 * they support fast (generally constant time) random access.  The primary
 * purpose of this interface is to allow generic algorithms to alter their
 * behavior to provide good performance when applied to either random or
 * sequential access lists.
 *
 * <p>The best algorithms for manipulating random access lists (such as
 * <tt>ArrayList</tt>) can produce quadratic behavior when applied to
 * sequential access lists (such as <tt>LinkedList</tt>).  Generic list
 * algorithms are encouraged to check whether the given list is an
 * <tt>instanceof</tt> this interface before applying an algorithm that would
 * provide poor performance if it were applied to a sequential access list,
 * and to alter their behavior if necessary to guarantee acceptable
 * performance.
 * 
 * <p>It is recognized that the distinction between random and sequential
 * access is often fuzzy.  For example, some <tt>List</tt> implementations
 * provide asymptotically linear access times if they get huge, but constant
 * access times in practice.  Such a <tt>List</tt> implementation
 * should generally implement this interface.  As a rule of thumb, a
 * <tt>List</tt> implementation should implement this interface if,
 * for typical instances of the class, this loop:
 * <pre>
 *     for (int i=0, n=list.size(); i &lt; n; i++)
 *         list.get(i);
 * </pre>
 * runs faster than this loop:
 * <pre>
 *     for (Iterator i=list.iterator(); i.hasNext(); )
 *         i.next();
 * </pre>
 *
 * <p>This interface is a member of the 
 * <a href="{@docRoot}/../guide/collections/index.html">
 * Java Collections Framework</a>.
 *
 */
public interface RandomAccess {
}
View Code

 

 

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()){}
    }
 1 package testrandomaccess;  
 2   
 3 import java.util.ArrayList;  
 4 import java.util.Iterator;  
 5 import java.util.LinkedList;  
 6 import java.util.List;  
 7 import java.util.RandomAccess;  
 8   
 9 /** 
10  * 
11  * @author bolong 
12  */  
13 public class TestRandomAccess {  
14 // 初始化列表  
15   
16     public static void initList(List list, int n) {  
17         for (int i = 0; i < n; i++) {  
18             list.add(i);  
19         }  
20     }  
21 //使用循环进行对列表的迭代  
22   
23     public static void traverseWithLoop(List list) {  
24         long starttime = 0;  
25         long endtime = 0;  
26         starttime = System.currentTimeMillis();  
27         for (int count = 0; count <= 1000; count++) {  
28             for (int i = 0; i < list.size(); i++) {  
29                 list.get(i);  
30             }  
31         }  
32         endtime = System.currentTimeMillis();  
33         System.out.println("使用loop迭代一共花了" + (endtime - starttime) + "ms时间");  
34   
35     }  
36 //使用迭代器对列表进行迭代  
37   
38     public static void traverseWithIterator(List list) {  
39         long starttime = 0;  
40         long endtime = 0;  
41         starttime = System.currentTimeMillis();  
42         for (int count = 0; count <= 1000; count++) {  
43             for (Iterator itr = list.iterator(); itr.hasNext();) {  
44                 itr.next();  
45             }  
46         }  
47         endtime = System.currentTimeMillis();  
48         System.out.println("使用Iterator迭代一共花了" + (endtime - starttime) + "ms时间");  
49     }  
50   
51     public static void traverse(List list) {  
52   
53         long starttime = 0;  
54         long endtime = 0;  
55         if (list instanceof RandomAccess) {  
56             System.out.println("该list实现了RandomAccess接口");  
57             starttime = System.currentTimeMillis();  
58             for (int count = 0; count <= 1000; count++) {  
59                 for (int i = 0; i < list.size(); i++) {  
60                     list.get(i);  
61                 }  
62             }  
63             endtime = System.currentTimeMillis();  
64             System.out.println("迭代一共花了" + (endtime - starttime) + "ms时间");  
65         } else {  
66             System.out.println("该list未实现RandomAccess接口");  
67             starttime = System.currentTimeMillis();  
68             for (int count = 0; count <= 1000; count++) {  
69                 for (Iterator itr = list.iterator(); itr.hasNext();) {  
70                     itr.next();  
71                 }  
72             }  
73             endtime = System.currentTimeMillis();  
74             System.out.println("迭代一共花了" + (endtime - starttime) + "ms时间");  
75         }  
76     }  
77   
78     public static void main(String[] args) {  
79         ArrayList arraylist = new ArrayList();  
80         LinkedList linkedlist = new LinkedList();  
81         initList(arraylist, 1000);  
82         initList(linkedlist, 1000);  
83         traverse(arraylist);  
84         traverse(linkedlist);  
85         traverseWithIterator(arraylist);  
86         traverseWithLoop(arraylist);  
87         traverseWithIterator(linkedlist);  
88         traverseWithLoop(linkedlist);  
89     }  
90 }  
验证RandomAccess的代码

根据程序输出的结果的确证明了,arraylist等实现了RandomAccess接口的类在进行迭代时使用loop效率更高,而linkedList那些未实现该接口的类在进行迭代时使用Iterator进行迭代效率更高.

posted @ 2016-03-07 14:24  人,总要有点追求的  阅读(964)  评论(0编辑  收藏  举报