在List集合这个大家族中,有许多类型的List
实现了RandomAccess
接口,那么这个接口有什么作用呢。
通过查看RandomAccess
的源码我们可以知道,这个接口用来表明支持快速随机访问。快速随机访问的速度能做到比线性访问的速度还要快。源码中也举了个例子做对比。
for (int i = 0, n = list.size(); i < n; i++)
list.get(i);
// runs faster than this loop:
for (Iterator i = list.iterator(); i.hasNext(); )
i.next();
通过get()方法(随机访问)
要比迭代器中的next()方法(线性访问)
速度要快。
再来看下List集合中两个常用的类 ArrayList
和 LinkedList
。
其中ArrayList
实现了RandomAccess
接口,而LinkedList
没有实现。我们测试一下二者通过随机访问和迭代器的线性访问的速度。
ArrayList
public class Test {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
list.add(i);
}
long start = System.nanoTime();
for (int i = 0, n = list.size(); i < n; i++) {
list.get(i);
}
long end = System.nanoTime();
System.out.println("实现了RandomAccess接口的随机访问时间: " + (end - start));
start = System.nanoTime();
for (Iterator<Integer> it = list.iterator(); it.hasNext(); ) {
it.next();
}
end = System.nanoTime();
System.out.println("实现了RandomAccess接口的线性访问时间: " + (end - start));
}
}
// 结果
实现了RandomAccess接口的随机访问时间: 341300
实现了RandomAccess接口的线性访问时间: 723400
LinkedList
public class Test {
public static void main(String[] args) {
List<Integer> list = new LinkedList<>();
for (int i = 0; i < 10000; i++) {
list.add(i);
}
long start = System.nanoTime();
for (int i = 0, n = list.size(); i < n; i++) {
list.get(i);
}
long end = System.nanoTime();
System.out.println("没有实现RandomAccess接口的随机访问时间: " + (end - start));
start = System.nanoTime();
for (Iterator<Integer> it = list.iterator(); it.hasNext(); ) {
it.next();
}
end = System.nanoTime();
System.out.println("没有实现RandomAccess接口的线性访问时间: " + (end - start));
}
}
// 结果
没有实现RandomAccess接口的随机访问时间: 33793400
没有实现RandomAccess接口的线性访问时间: 867900
可以看出,实现了RandomAccess
接口的情况下,随机访问的速度更快;没有实现RandomAccess
接口的情况下,线性访问更快。所以遍历集合时,不同的遍历方式的效率也是不同的,我们要根据情况选择遍历方式,提高性能。
在JDK的源码中也有其它地方用到了这个特性。
比如Collections
类中的binarySearch()
方法
public static <T>
int binarySearch(List<? extends Comparable<? super T>> list, T key) {
// 判断是否实现了RandomAccess 接口
if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
return Collections.indexedBinarySearch(list, key);
else
return Collections.iteratorBinarySearch(list, key);
}
该方法中根据是否实现了RandomAccess
接口而采用不用的搜索方式。
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
}
总结:
RandomAccess
接口支持快速随机访问。访问速度大于线性访问- 实现了
RandomAccess
接口的集合类,随机访问速度大于线性访问速度;未实现RandomAccess
接口的集合类,线性访问速度大于随机访问速度 - 集合类常用
迭代器(Iterator)
的方式实现线性访问