绝大多数日常场景下应优先使用ArrayList,因其CPU缓存友好、随机访问快、内存占用小且JVM优化充分;仅在需高频头尾增删且完全不访问中间索引时才考虑LinkedList。
什么时候该用
而不是
绝大多数日常场景下,
是更优选择。它底层是动态数组,CPU缓存友好、随机访问快、内存占用小,且现代JVM对数组做了大量优化。
常见适用场景包括:
频繁按索引读取元素(
),比如遍历、查找、分页
批量添加末尾元素(
),扩容摊还成本低(
)
需要与数组互转(
/
)
使用
或第三方库(如 Apache Commons Collections),它们内部多针对数组结构优化
注意:
在中间插入/删除(
/
)仍是
,但实际性能往往比
的指针操作更快——因为避免了对象分配、GC压力和缓存不命中。
哪些情况真有必要选
唯一不可替代的用途是:需要在**头尾高频增删**,且**完全不访问中间索引**。
立即学习
“
Java免费学习笔记(深入)
”;
典型例子:
实现栈(
→
)
实现队列(
→
)
作为双端队列(
)参与线程安全的生产者-消费者逻辑(但此时应优先考虑
)
不要因为它“链表”就默认支持快速插入——
是
遍历,比
慢一个数量级。实测在 10k 元素时,随机访问慢 5–10 倍。
Eclipse导入Android或其他的JAVA项目的正确方法 WORD版
本文档主要讲述的是Eclipse导入Android或其他的JAVA项目的正确方法;希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
下载
在两者中的行为差异
表面签名一致,底层代价天差地别:
:先将索引
及之后所有元素右移一位(数组拷贝),再插入;最坏
,但全是连续内存复制,CPU效率高
:先从头或尾遍历到第
个节点(取决于
靠近哪端),再修改前后指针;平均
,且每次遍历都是非连续内存访问,容易触发缓存失效
尤其当
接近中间位置时,
不仅没优势,反而更慢。JDK 源码里甚至为
的
做了方向优化(从 head 或 tail 走更短路径),但这无法抵消硬件层面的劣势。
内存开销与 GC 影响常被低估
每个元素额外持有两个引用(
和
),加上对象头、对齐填充,单个节点通常占 24–32
字节
;而
的元素直接存入数组,无额外引用开销。
例如存 10 万个
:
更大的问题是:
创建大量短期存活的小对象(每个节点),加剧 Young GC 频率。在吞吐敏感或内存受限服务中,这点可能成为瓶颈。
真实项目中,除非明确压测证明
在特定操作上胜出,否则默认用
;若需高效头尾操作,优先查
——它用循环数组实现,兼具
的内存效率和
的头尾操作性能。
ArrayListLinkedListArrayListget(i)add(e)O(1)toArray()Arrays.asList()StreamArrayListadd(i, e)remove(i)O(n)LinkedListLinkedListLinkedListpush/popaddFirst()/removeFirst()offer/polladdLast()/removeFirst()DequeConcurrentLinkedQueueLinkedList.get(i)O(n)ArrayListadd(index, element)ArrayList.add(i, e)iO(n)LinkedList.add(i, e)iiO(n/2)iLinkedListLinkedListget(i)LinkedListprevnextArrayListIntegerArrayList: ~100_000 × 4B (int) + 数组头 ≈ 400KB
LinkedList: ~100_000 × (24–32B) ≈ 2.4–3.2MBLinkedListLinkedListArrayListArrayDequeArrayListLinkedList