该接口属于标志(mark)接口,不提供任何接口方法或变量,但是实现该接口的支持随机访问,一说到这里就开始奇怪了,一个空接口怎么会支持随机访问,实际上不是该接口支持随机访问,这里涉及到一个设计问题,先看官文的解析:
(English)It is recognized that the distinction between random and sequentialaccess is often fuzzy. For example, some List implementationsprovide asymptotically linear access times if they get huge, but constantaccess times in practice. Such a List implementationshould generally implement this interface. As a rule of thumb, a List implementation should implement this interface if,for typical instances of the class, this loop:
(Chinese)人们认识到,随机访问和顺序访问之间的区别通常是模糊的。 例如,一些List实现提供渐近的线性访问时间,如果它们在实践中获得巨大但是恒定的访问时间。 这样的一个List实现应该通常实现这个接口。 根据经验, 一个List的实现应实现此接口,如果对于类的典型实例,此循环:
for (int i=0, n=list.size(); i < n; i++)
list.get(i);
比这个循环运行得更快:
for (Iterator i=list.iterator(); i.hasNext(); )
i.next();
此接口是成员Java Collections Framework 。
啥意思?人们都知道Array是可以随机访问的,根据上面的典型实例的循环,也就是说ArrayList通过普通的for循环会比使用迭代器来遍历List更快,如果是LinkedList,根据链表添加删除元素容易,查找元素困难的特点,普通的for循环会更加消耗性能,使用迭代器反而会更快,也就是说,实现RandomAccess接口的都支持随机访问,也就是普通的for遍历比迭代器性能更优。
测试代码:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
public class test{
ArrayList<Integer> aList = new ArrayList<Integer>(100000);
LinkedList<Integer> lList = new LinkedList<Integer>();
public void addE() {
int i = 0;
while(i<100000) {
aList.add(i);
lList.add(i);
i++;
}
}
public void AListUseTime() {
Integer num = 0;
long start1 = System.currentTimeMillis();
for(int i =0; i < aList.size();i++) {
num = aList.get(i);
}
long end1 = System.currentTimeMillis();
System.out.println("ArrayList:普通For遍历使用时间"+(end1-start1));
long start2 = System.currentTimeMillis();
for(Iterator<Integer> list = aList.iterator(); list.hasNext();) {
num = list.next();
}
long end2 = System.currentTimeMillis();
System.out.println("ArrayList:迭代器遍历使用时间"+(end2-start2));
}
public void LListUseTime() {
Integer num = 0;
long start1 = System.currentTimeMillis();
for(int i =0; i < lList.size();i++) {
num = lList.get(i);
}
long end1 = System.currentTimeMillis();
System.out.println("LinkedList:普通For遍历使用时间"+(end1-start1));
long start2 = System.currentTimeMillis();
for(Iterator<Integer> list = lList.iterator(); list.hasNext();) {
num = list.next();
}
long end2 = System.currentTimeMillis();
System.out.println("LinkedList:迭代器遍历使用时间"+(end2-start2));
}
public static void main(String[] args) {
final test ts = new test();
ts.addE();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
ts.AListUseTime();
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
ts.LListUseTime();
}
}, "t2");
t1.start();
t2.start();
}
}
显示结果:
ArrayList:普通For遍历使用时间4
ArrayList:迭代器遍历使用时间2
LinkedList:普通For遍历使用时间4990
LinkedList:迭代器遍历使用时间2
通过调整List的大小进行多测实验得出结论:实际上对于ArrayList无论采取哪一种遍历方式其速度都差不多,但对于LinkedList就不一样,并不支持随机访问,直接通过for的形式每次都会i++获取一个index,每次查找元素的时候都会重新遍历List,因此会遍历list.size()次list,所以特别耗时,因此对于LinkedList在实际生产中最好不要直接遍历,还是通过迭代器进行顺序遍历吧。
集合操作类Collections中的二叉搜索算法对实现RandomAccess接口的类的处理:
binarySearch API解释:
使用二叉搜索算法搜索指定对象的指定列表。 在进行此呼叫之前,列表必须根据指定的比较器(如sort(List, Comparator)方法)按升序排序。 如果没有排序,结果是未定义的。 如果列表包含与指定对象相等的多个元素,则不能保证将找到哪个元素。
该方法以log(n)时间运行“随机访问”列表(提供近常数位置访问)。 如果指定的列表没有实现RandomAccess接口并且很大,则该方法将执行基于迭代器的二进制搜索,执行O(n)链接遍历和O(log n)元素比较。
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);
}
private static <T>
int indexedBinarySearch(List<? extends Comparable<? super T>> list, T key) {
int low = 0;
int high = list.size()-1;
while (low <= high) {
int mid = (low + high) >>> 1;
Comparable<? super T> midVal = list.get(mid);
int cmp = midVal.compareTo(key);
if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found
}
private static <T>
int iteratorBinarySearch(List<? extends Comparable<? super T>> list, T key)
{
int low = 0;
int high = list.size()-1;
ListIterator<? extends Comparable<? super T>> i = list.listIterator();
while (low <= high) {
int mid = (low + high) >>> 1;
Comparable<? super T> midVal = get(i, mid);
int cmp = midVal.compareTo(key);
if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found
}
实际生成怎么用?根据集合操作类Collections来写啊,例如
if (list instanceof RandomAccess)
//普通for遍历
else
//迭代器遍历