在List中有一个独立的接口:RandomAccess接口,Vector和ArrayList实现了该接口,而LinkedList却未实现该接口。查看该接口源码发现这居然是一个空的接口。

public interface RandomAccess {
}

那么这个空接口起到了什么作用呢?

该接口的注释中有这么一段话:

 * 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 < n; i++)
 *         list.get(i);
 * </pre>
 * runs faster than this loop:
 * <pre>
 *     for (Iterator i=list.iterator(); i.hasNext(); )
 *         i.next();
 * </pre>

解释说明了,实现了该接口的类再使用for循环进行遍历时,会比使用iterator进行遍历快(这里需要注意的是,意思并非是实现了该接口后的效应,而是有这一特性的类去实现了该接口)。同时说明对于那种随机访问且数据变动不大的的(如:数组)通常应该实现该接口。

而ArrayList和Vector的底层实现便是数组实现的,这两个类便实现了RandomAccess接口,以链表实现的LinkedList则未实现该接口。

ArrayList与LinkedList 分别使用for循环遍历及其iterator遍历速度比较结果如下(单位ms):

数据量ArrayList:forArrayList:iteratorLinedList:forLinedList:iterator
500021203921
500001711811180180
50000018601669非常久1924

可知当数据量较小时二者区别不大, 当数据量达到万级别时,arrayList使用for循环的优势便显现出来了,linkedList若使用for循环其遍历效率尤其的低。

因此在遍历时就可以,使用instanceof 来判断是否实现RandomAccess接口,来有选择的根据实现类来下选择遍历方式。

其中在Collections类中的binarySearch()方法便是用该种方式来判断list实现的是linkedList还是arrayList

public static <T>
    int binarySearch(List<? extends Comparable<? super T>> list, T key) {
    if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
        return Collections.indexedBinarySearch(list, key);
    else
        return Collections.iteratorBinarySearch(list, key);
}

该二分法查询便是先进行判断该list的实现类是否实现了RandomAccess接口,若实现了则使用索引式的二分法,若未实现则使用迭代器式的二分法。

总结:RandomAccess用来当标记,是一种标记接口。用处是当要实现某些算法时,会判断当前类是否实现了RandomAccess接口,会选择不同的算法。

接口RandomAccess中内容是空的,只是作为标记用。比如List下的ArrayList和LinkedList。其中ArrayList实现了RandomAccess。而LinkedList没有。我们可以利用instanceof来判断哪一个是实现了RandomAccess。分辨出两个集合。其中ArrayList使用for循环遍历快,而LinkedList使用迭代器快。那么通过分辨,不同的集合使用不同的遍历方式。


标题:关于RandomAccess接口作用
作者:JonLv
地址:http://39.108.183.139:8080/articles/2023/03/11/1678547470097.html