theme: channing-cyan
这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战
接着上一篇《Java集合框架 | ArrayList、Vector、LinkedList(一)》,对比了ArrayList和Vector,这篇文章来对比ArrayList和LinkedList。
二、ArrayList 和LinkedList比较
上面的文章内容有讲到了ArrayList和Vector的区别,之所以把两者进行对比分析是因为两者的底层实现都是动态的数组。因为ArrayList是线程不安全的,我们这一段落的内容拿ArrayList去比较同样线程不安全的LinkedList。
Linkedlist 被实现为一个双向的链表。它在 add 和 remove 上的性能优于数组列表,但在 get 和 set 方法上性能较差。
对比源码中两个类的定义。
ArrayList
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
LinkedList
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable
对比后清晰的发现,LinkedList比ArrayList多实现了Deque
队列接口,但比ArrayList少实现了RandomAccess随机存储的接口。所以LinkedList提供了操作队列的接口Deque,支持对集合两端的有效访问,如 offer ()
、peek ()
、 poll ()
等。
但LinkedList缺少实现RandomAccess接口,代表LinkedList不支持随机存储,也就是通过顺序访问, 查询速度慢, 增删元素快。ArrayList支持随机访问, 查询速度快, 增删元素慢。所以对应的 ArrayList查询速度快,LinkedList
查询速度慢, RandomAccess 这个标记接口就是标记能够随机访问元素的集合, 简单来说就是底层是数组实现的集合。
RandomAccess 这个接口只是一个空接口,所以是做标记用的,那么我们能用来干什么呢?当然是检测集合类是够实现了这个接口,然后使用对应的遍历方式。即实现了RandomAccess接口,不使用迭代器访问,没有实现的,使用迭代器访问。
常用操作时间复杂度
| | ArrayList | LinkedList | | -------- | --------- | ---------- | | get() | O(1) | O(n) | | add() | O(1) | O(1) | | remove() | O(n) | O(n) |
对比总结
| | ArrayList | LinkedList | | ------ | ------------------------------------------- | ------------------------------------------- | | 扩容机制 | 底层实现是一个数组,可初始化大小,有扩容机制,触发扩容机制后,扩容到原有容量的1.5倍 | 底层是用双向链表实现的,没有初始化大小,所以没有扩容机制,一直在前面增加或后面增加即可 | | 继承实现 | 实现List、RandomAccess接口 | 实现List、Deque接口 | | 插入删除 | 在结构的中间操作,需要进行位移 | 在任何地方操作,都不需要进行位移 | | 优势 | 更适合静态存储和读取访问 | 更适合存储静态数据,适合删除,插入操作 |
总之,我们应该首先选LinkedList,如果使用的场景具备一下的条件:
- 元素没有大量的随机存取
- 有大量的添加/删除操作