zoukankan      html  css  js  c++  java
  • 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进行迭代效率更高.

  • 相关阅读:
    MySQL核心知识学习之路()
    软件设计之路(5)
    软件设计之路(4)
    软件设计之路(4)
    软件设计之路(3)
    软件设计之路(2)
    软件设计之美-软件设计之路
    js将 “2021-07-06T06:23:57.000+00:00” 转换为年月日时分秒
    git pull/push 拉取/推送指定分支的代码
    git clone 指定分支的代码
  • 原文地址:https://www.cnblogs.com/zhilu-doc/p/5250417.html
Copyright © 2011-2022 走看看