LinkedList适合首尾插入删除和用作栈/队列,因底层是双向链表;不适合随机访问或索引查找,get()需遍历节点,时间复杂度O(n),而ArrayList为O(1)。
LinkedList适合频繁在列表首尾进行插入和删除的操作,不适合随机访问或按索引查找。它的底层是双向链表,没有连续内存地址,所以get(int index)需要从头或尾遍历节点,时间复杂度为O(n)。
addFirst()、addLast()、removeFirst()、removeLast()时性能优于ArrayListpush()/pop())或队列(offer()/poll())非常自然,因为这些方法都直接映射到链表头尾操作get(i)或set(i, e)会明显拖慢性能,尤其当列表较大时因为LinkedList.get(int index)内部会先判断索引靠近头部还是尾部,再决定从first还是last开始遍历,但无论如何都要跳过最多n/2个节点。而ArrayList直接通过数组下标访问,是O(1)。
看这个对比:
LinkedListlist = new LinkedList<>(); for (int i = 0; i < 10000; i++) list.add("item" + i); String s = list.get(9999); // 实际要遍历约5000个节点
如果业务逻辑中存在类似list.get(i)在循环里反复调用,即使i变化不大,也建议改用Iterator或换成ArrayList。
的注意事项LinkedList实现了Deque接口,所以它能天然支持双端队列语义。但要注意:它不是线程安全的,多线程环境下必须手动同步,或者改用ConcurrentLinkedDeque。
add()和offer()都往尾部加,但add()失败时抛IllegalStateException,offer()返回false
remove()和poll()都从头部取,但remove()为空时抛NoSuchElementException,poll()返回null
push()/pop()模拟栈时,实际操作的是头部,和addFirst()/removeFirst()等价每个Node对象除了存数据,还要存prev和next引用,在32位JVM上额外占8字节,64位(开启指针压缩)也至少占16字节。这意味着同样存1万个字符串,LinkedList比ArrayList多占用数万字节内存。
ConcurrentLinkedDeque
for (int i = 0; i 的人,得先想清楚自己到底在操作什么。