Java ArrayList 为什么要实现 RandomAccess 接口?
在我们的开发中,List接口是最常见不过,而且我们几乎每天都在用ArrayList或者LinkedList,但是细心的同学有没有发现,ArrayList中实现了RandomAccess接口,而LinkedList却没有实现RandomAccess接口,这是为什么呢?
public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable
public class LinkedList<E>extends AbstractSequentialList<E>implements List<E>, Deque<E>, Cloneable, java.io.Serializable
RandomAccess接口中是空的,RandomAccess接口又是什么呢?
public interface RandomAccess {
}
RandomAccess接口
RandomAccess是一个标记接口,官方解释是只要List实现这个接口,就能支持快速随机访问。而什么是随机访问呢?接下来我们来举例说明。
Collections是集合的一个工具类,我们看一下Collections源码中的二分搜索方法。
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);elsereturn Collections.iteratorBinarySearch(list, key);}
在源码中可以看出,判断list是否是RandomAccess的实例,如果是,则执行indexedBinarySearch方法,如果不是,则执行iteratorBinarySearch方法。接下来看一下这两个方法。
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;elsereturn 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;elsereturn mid; // key found}return -(low + 1); // key not found
}
上述两个方法的源码表示,实现了RandomAccess接口的List使用索引遍历,而未实现RandomAccess接口的List使用迭代器遍历。那么为什么要这么设计呢?
既然涉及到二分搜索的遍历操作,那么现在我们来分析一下ArrayList和LinkedList遍历元素的性能如何?
public class CollectionTest {public static void main(String[] args){long arrayListIndexedTime = arrayListIndexed();long arrayListIteratorTime = arrayListIterator();long linkedListIndexedTime = linkedListIndexed();long linkedListIteratorTime = linkedListIterator();System.out.println("测试ArrayList通过for遍历所消耗时间:" + arrayListIndexedTime);System.out.println("测试ArrayList通过iterator遍历所消耗时间:" + arrayListIteratorTime);System.out.println("测试LinkedList通过for遍历所消耗时间:" + linkedListIndexedTime);System.out.println("测试LinkedList通过iterator遍历所消耗时间:" + linkedListIteratorTime);}//测试ArrayList通过for遍历所消耗时间public static long arrayListIndexed() {List<Integer> arrayList = new ArrayList<>();for (int i = 0; i < 10000; i++) {arrayList.add(i);}//记录开始时间long startTime = System.currentTimeMillis();for (int i = 0; i < arrayList.size(); i++) {arrayList.get(i);}//记录结束时间long endTime = System.currentTimeMillis();//遍历消耗时间long resultTime = endTime - startTime;return resultTime;}//测试ArrayList通过iterator遍历所消耗时间public static long arrayListIterator() {List<Integer> arrayList = new ArrayList<>();for (int i = 0; i < 10000; i++) {arrayList.add(i);}//记录开始时间long startTime = System.currentTimeMillis();Iterator<Integer> iterator = arrayList.iterator();while (iterator.hasNext()) {iterator.next();}//记录结束时间long endTime = System.currentTimeMillis();//遍历消耗时间long resultTime = endTime - startTime;return resultTime;}//测试LinkedList通过for遍历所消耗时间public static long linkedListIndexed() {List<Integer> linkedList = new LinkedList<>();for (int i = 0; i < 10000; i++) {linkedList.add(i);}//记录开始时间long startTime = System.currentTimeMillis();for (int i = 0; i < linkedList.size(); i++) {linkedList.get(i);}//记录结束时间long endTime = System.currentTimeMillis();//遍历消耗时间long resultTime = endTime - startTime;return resultTime;}//测试LinkedList通过iterator遍历所消耗时间public static long linkedListIterator() {List<Integer> linkedList = new LinkedList<>();for (int i = 0; i < 10000; i++) {linkedList.add(i);}//记录开始时间long startTime = System.currentTimeMillis();Iterator<Integer> iterator = linkedList.iterator();while (iterator.hasNext()) {iterator.next();}//记录结束时间long endTime = System.currentTimeMillis();//遍历消耗时间long resultTime = endTime - startTime;return resultTime;}
}
测试结果如下
测试ArrayList通过for遍历所消耗时间:1
测试ArrayList通过iterator遍历所消耗时间:2
测试LinkedList通过for遍历所消耗时间:47
测试LinkedList通过iterator遍历所消耗时间:1
我们来分析一下测试结果:ArrayList通过for遍历比通过iterator遍历要稍快,LinkedList通过iterator遍历比通过for遍历要快。
所以说在我们的应用中,要考虑使用List接口的哪种实现类,可以更好更高效的满足实际场景需求。所以在这里通过实现RandomAccess接口来区分List的哪种实现类。
总结
最后总结一句话:实现RandomAccess接口的List可以通过for循环来遍历数据比使用iterator遍历数据更高效,未实现RandomAccess接口的List可以通过iterator遍历数据比使用for循环来遍历数据更高效。
Java ArrayList 为什么要实现 RandomAccess 接口?相关推荐
- 【Java】ArrayList 为啥要实现 RandomAccess 接口
1.概述 转载:http://www.javastack.cn/article/2019/why-arraylist-impl-randomaccess-interface/ 在我们的开发中,List ...
- ArrayList 为什么要实现 RandomAccess 接口?
点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 来源 | http://t.cn/AilfR3YW 在我们的开发中 ...
- 开课吧之Java常见面试题之RandomAccess接口
RandomAccess接口?* 查看源码我们发现实际上 RandomAccess 接口中什么都没有定义.所以,在我看来 RandomAccess 接口不过是一个标识罢了.标识什么? 标识实现这个接口 ...
- JAVA中RandomAccess接口
RandomAccess接口 RandomAccess是一个标记接口,实现该接口表示支持快速访问.这是一个空接口,没有任何方法. 当实现该接口时,说明支持快速访问. 即: for (int i=0, ...
- java arraylist线程安全_ArrayList升级为线程安全的List
我们都熟知在高并发的场景下,ArrayList是线程不安全的,JDK Collections接口提供线程安全的操作,本文通过代码演示下,最后查看源码分析下为何是线程安全的. ArrayList升级为线 ...
- RandomAccess接口
RandomAccess是一个标记接口,实现该接口表示支持快速访问.这是一个空接口,没有任何方法. 当实现该接口时,说明支持快速访问. 即: for (int i=0, n=list.size(); ...
- ArrayList集合类实现的RandomAccess空接口有何用?
相信不少小伙伴在查看 ArrayList 集合时发现该集合类实现了一个 RandomAccess 空实现的接口,源码如下 ⬇️ ArrayList 源码: RandomAccess 接口源码: 可以看 ...
- Java编程:RandomAccess接口
RandomAccess 是一个标记接口,标识实现该接口的类支持快速随机访问. 一.随机访问和串行访问 举个例子:在 Java 中,有 ArrayList 和 LinkedList 两种数据类型. A ...
- ArrayList集合实现RandomAccess接口有何作用?为何LinkedList集合却没实现这接口?
众所周知,在List集合中,我们经常会用到ArrayList以及LinkedList集合,但是通过查看源码,就会发现ArrayList实现RandomAccess接口,但是RandomAccess接口 ...
最新文章
- c语言报告程序分析报告,2012C语言程序分析报告.doc
- Spring Boot 2.0 新特性和发展方向
- 你真的了解NSNotificationCenter吗?
- Intel Realsense D435 多摄像头配置 Multi-camera configurations (220)(官方测试的摄像头配置表【不同带宽下分辨率、帧率等】)
- Cannot re-initialize CUDA in forked subprocess. To use CUDA with multiprocessing, you
- select下拉框带模糊查询_SQL 之 简单查询
- 黑鲨怎么修改服务器,黑鲨研习win7系统DNS服务器更换的还原教程
- Android开发周报:Android 8.0开始推送、微店插件化实践
- java url链接超时_Java HttpURLConnection超时和IO异常处理
- iview(DatePicker)时间转入后台少一天 解决方案
- QQ空间相册批量下载qq相册批量下载专家比骨头小林还厉害
- wdr7660虚拟服务器设置,TP-Link TL-WDR7660无线桥接怎么设置?
- 如何做网络投票的刷票外挂(二)
- 大数据是什么,大数据的特点主要有哪些,应该怎么运用?
- 2021年华数杯数学建模B题进出口公司的货物装运策略求解全过程文档及程序
- 由浅入深读透vue源码:diff算法
- LeetCode——面试题 10.11. 峰与谷(JAVA)
- 杜家坎装甲兵工程学院计算机二级考点,从丰台区杜家坎到东城区东十四条怎么走??...
- classes是什么意思怎么读_淦怎么读音 淦是什么意思
- microsoft office visio 2007 安装过程中出错的解决(直接看后面)
热门文章
- MATLAB语言中的关系与逻辑运算
- 类的继承定义一个computer类在此基础上派生出两个子类(继承与多态绑定)
- 阿里云高级技术专家空见: CDN的数据化之路
- Wowza Media Server媒体服务器应用
- 中文URL是否有利于网站SEO
- 不越狱无硬件,轻松搞定iPhone投影与录屏
- 关键词多样性的重要意义
- OpenCV学习笔记(3)——Scalar数据类型理解
- jovi智慧场景运动步怎么是零_Jovi智慧场景,赛事直播提前提醒,让你不错过任何一刻的精彩...
- winsever 2008 r2 管理员账号没有权限_钉钉管理员攻略—主管理员①