Java集合框架 | ArrayList、Vector、LinkedList(二)

920 阅读2分钟

这是我参与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接口,不使用迭代器访问,没有实现的,使用迭代器访问

常用操作时间复杂度

ArrayListLinkedList
get()O(1)O(n)
add()O(1)O(1)
remove()O(n)O(n)

对比总结

ArrayListLinkedList
扩容机制底层实现是一个数组,可初始化大小,有扩容机制,触发扩容机制后,扩容到原有容量的1.5倍底层是用双向链表实现的,没有初始化大小,所以没有扩容机制,一直在前面增加或后面增加即可
继承实现实现List、RandomAccess接口实现List、Deque接口
插入删除在结构的中间操作,需要进行位移在任何地方操作,都不需要进行位移
优势更适合静态存储和读取访问更适合存储静态数据,适合删除,插入操作

总之,我们应该首先选LinkedList,如果使用的场景具备一下的条件:

  • 元素没有大量的随机存取
  • 有大量的添加/删除操作