在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:for | ArrayList:iterator | LinedList:for | LinedList:iterator |
---|---|---|---|---|
5000 | 21 | 20 | 39 | 21 |
50000 | 171 | 181 | 1180 | 180 |
500000 | 1860 | 1669 | 非常久 | 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使用迭代器快。那么通过分辨,不同的集合使用不同的遍历方式。