这篇文章是来自知乎上的一个问题。
相信很多人在面试时都被问过这个问题,然后一般回答:ArrayList在指定下标访问时快,LinkedList在插入/删除元素时快。
其实这是一种人云亦云的谬误。可能最初有人这么回答,然后不加验证地转来转去,后面就成了八股文中的“标准答案”。
这个问题其实早在2015年,就由作者Joshua Bloch在Twitter上给出了回答:“有人真的使用过LinkedList吗?我写了它,但是我从没用过”。
以下是我在知乎上的回答。
——————————————————————————————————————————————————————————
先说结论:需要List的场合,绝大部分情况下选择ArrayList;需要Queue或Stack的场合,绝大部分情况下选择ArrayDeque。
看实际的性能测试。对ArrayList和LinkedList分别做100000次以下操作,统计执行时间(ms):
尾部插入 | 头部插入 | 中间插入 | 遍历 | |
---|---|---|---|---|
ArrayList | 5 | 346 | 152 | 7 |
LinkedList | 2 | 4 | 5044 | 2 |
逐条分析解释:
除了上述时间消耗的比较,在空间消耗上ArrayList也优于LinkedList。虽然ArrayList会扩容到1.5倍,但是LinkedList内部为每个存储元素封装了Node对象,除了Node对象头部,还要保存前后Node的地址和当前存储元素的地址,实际上LinkedList占用内存要远大于ArrayList。
结论:仅在头部插入/删除时,LinkedList在时间上有性能优势。
不过问题来了:既然你需要在头部频繁插入/删除,那么为什么不选择更合适的数据结构呢?比如Stack或者Queue。
那么LinkedList是实现这两种数据结构的最优选择吗?答案也不是,而是ArrayDeque。
不多说,再看性能测试对比。对ArrayDeque和LinkedList分别做1000000次以下操作,统计执行时间(ms):
头部插入 | 尾部插入 | 遍历 | |
---|---|---|---|
ArrayList | 12 | 126 | 6 |
LinkedList | 61 | 153 | 10 |
可以看出,ArrayDeque在每项时间指标都优于LinkedList。另外在空间上,ArrayDeque底层使用的循环数组也是优于LinkedList使用的Node链表。
结论:无论在时间还是空间上,ArrayDeque都优于LinkedList。
顺便说一句,JDK中还提供了Stack类。虽然它名字就叫Stack,一般不会用到它实现栈,甚至Java官方都建议不要使用它。因为有以下缺陷:
那么综合看来,LinkedList是否一无是处呢?我觉得它的存在还是有一定价值的: