RandomAccess接口有什么用 RandomAccess接口

最近在看ArrayList源码 , 发现ArrayList实现了一个很特别的接口:java.util.RandomAccess 。
public interface RandomAccess{}
这个接口没有任何东西 , 和java.lang.Cloneable、java.io.Serializable一样 , 只是一个标记接口 , 它的作用是什么呢?

注释里写的是 , 这是一个标记接口 , 表明实现了这个接口的类是支持快速随机访问的 。
什么意思呢?就是说实现了这个接口的集合 , 代表它支持通过下标来快速访问元素 , 例如ArrayList 。

像LinkedList就没有实现这个接口 , 因为LinkedList是链表的结构 , 没有下标 , 不支持快速随机访问 , 虽然LinkedList也有get(int index)方法 , 但是它的效率非常低 , 是通过节点的next属性不断向后寻找的 。

至于为什么ArrayList支持快速随机访问 , 可以看笔者另外一篇文章:长度一百万的数组 , get(0)和get(999999)性能有区别吗?

注释里还给出了例子 , 如果类实现了该接口 , 那么通过for循环遍历性能会更好一些 , 反之 , 则通过迭代器遍历 。

总之这个接口的目的就是判断集合类是否支持快速随机访问 , 好让开发者可以优先使用更好的算法来遍历集合 。如果实现了该类那么就优先使用for循环遍历集合 , 否则就通过迭代器的模式来遍历 。
实战

比较一下不同的集合 , 通过不同的方式遍历的性能 。
public class ListTest {public static void main(String[] args) {Object o = new Object();List list = new ArrayList();for (int i = 0; i < 100000; i++) {list.add(o);}foreach(list);iterate(list);System.out.println("-------------");list = new LinkedList();for (int i = 0; i < 1000; i++) {//LinkedList for循环遍历太慢 , 故减少长度list.add(o);}foreach(list);iterate(list);}static void foreach(List list) {long t1 = System.currentTimeMillis();for (int i = 0; i < 10000; i++) {for (int k = 0; k < list.size(); k++) {list.get(k);}}System.err.println(list.getClass().getSimpleName() + ":for循环:" + (System.currentTimeMillis() - t1));}static void iterate(List list) {long t1 = System.currentTimeMillis();for (int i = 0; i < 10000; i++) {Iterator iterator = list.iterator();while (iterator.hasNext()) {iterator.next();}}System.err.println(list.getClass().getSimpleName() + ":迭代器:" + (System.currentTimeMillis() - t1));}}

程序运行结果:


RandomAccess接口有什么用 RandomAccess接口

文章插图

验证了上述结论:支持快速随机访问的 , for循环遍历更高效 , 反之 , 迭代器模式更高效 。

因此 , 我们可以通过集合类是否实现了RandomAccess接口 , 来选择更好的遍历方式 , 遍历方法可优化为:
【RandomAccess接口有什么用 RandomAccess接口】static void traverse(List list) {if (list instanceof RandomAccess) {// 支持快速随机访问int size = list.size();for (int i = 0; i < size; i++) {list.get(i);}}else {Iterator iterator = list.iterator();while (iterator.hasNext()) {iterator.next();}}}