Java 中 ArrayList 和 LinkedList 有什么区别?

一、底层数据结构

特性 ArrayList LinkedList
实现方式 基于动态数组 基于双向链表
内存布局 连续内存块,支持快速随机访问 离散节点,每个节点包含数据及前后指针
默认初始容量 10(扩容时增长 50%) 无预分配容量,动态添加节点

二、核心操作性能对比

java 复制代码
// ArrayList的随机访问示例
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(1);
int val1 = arrayList.get(0);  // O(1)

// LinkedList的顺序访问示例
LinkedList<Integer> linkedList = new LinkedList<>();
linkedList.add(1);
int val2 = linkedList.get(0);  // O(n)
操作 ArrayList 时间复杂度 LinkedList 时间复杂度
随机访问(get/set) O(1) O(n)
头部插入/删除 O(n)(需移动元素) O(1)
尾部插入/删除 分摊 O(1)(无扩容时 O(1)) O(1)
中间插入/删除 O(n) O(n)(需遍历到目标位置)

三、内存与 GC 影响

维度 ArrayList LinkedList
内存占用 仅存储元素 + 数组头(内存紧凑) 每个节点额外存储两个指针(对象头 + 前后引用)
GC 压力 整体回收高效(单个数组对象) 频繁增删产生大量小对象,增加 GC 负担
缓存局部性 高(连续内存,CPU 预加载命中率高) 低(节点分散,缓存未命中率高)

四、扩容机制

  • ArrayList 扩容流程

    java 复制代码
    // 扩容核心逻辑(JDK17)
    int newCapacity = oldCapacity + (oldCapacity >> 1); // 1.5倍扩容
    elementData = Arrays.copyOf(elementData, newCapacity);
    • 代价:数据复制导致 O(n) 时间复杂度
    • 优化建议 :初始化时预估容量(new ArrayList<>(initialCapacity)
  • LinkedList 无扩容:动态添加节点,但每个节点额外占用 24 字节(64 位 JVM)

五、线程安全与并发方案

方案 ArrayList LinkedList
默认线程安全
同步包装类 Collections.synchronizedList() Collections.synchronizedList()
高并发替代方案 CopyOnWriteArrayList ConcurrentLinkedDeque

六、工程实践场景

1. 电商商品列表展示

  • 选择 ArrayList

    • 高频读取商品信息(随机访问)
    • 批量更新时通过尾插法优化(addAll()
    java 复制代码
    List<Product> products = new ArrayList<>(10000); // 预分配容量

2. 实时消息队列

  • 选择 LinkedList

    • 高频头尾操作(addFirst()/removeLast()
    • 使用迭代器避免随机访问:
    java 复制代码
    LinkedList<Message> queue = new LinkedList<>();
    // 生产者
    queue.offer(new Message());
    // 消费者(高效遍历)
    Iterator<Message> it = queue.iterator();
    while(it.hasNext()) process(it.next());

3. 多线程日志处理器

  • 选择 CopyOnWriteArrayList

    • 写操作极少(日志初始化配置)
    • 高频遍历读取日志规则
    java 复制代码
    CopyOnWriteArrayList<LogRule> rules = new CopyOnWriteArrayList<>();
    // 写操作(仅在配置更新时触发)
    rules.add(new LogRule());
    // 读操作(无锁并发)
    rules.forEach(LogService::applyRule);

七、性能对比测试数据

测试环境:JDK17,10 万次操作,i7-11800H

测试场景 ArrayList 耗时 LinkedList 耗时 差异原因
随机访问 1 万次 2ms 650ms 数组 O(1) vs 链表 O(n) 遍历
尾部插入 1 万次 3ms 5ms 均摊 O(1),链表节点创建开销略高
头部插入 1 万次 420ms 8ms 数组需移动元素,链表直接修改指针
遍历所有元素 15ms 18ms 数组缓存命中率高

八、高级特性对比

特性 ArrayList LinkedList
实现接口 List List + Deque
序列化效率 高(连续数据,可批量写入) 低(需逐个节点处理)
内存池兼容性 适合对象池化(数组整体复用) 节点分散,池化效果差
批量操作优化 System.arraycopy() 高效 需要逐个节点操作

九、选型决策树

随机访问/遍历 频繁头尾增删 是 否 是 否 需要List结构? 主要操作类型 ArrayList LinkedList 是否需要线程安全? CopyOnWriteArrayList ArrayList 是否需要双端队列? LinkedList 考虑ArrayDeque


通过以上对比,开发者可根据具体场景选择最合适的实现:

  • 优先 ArrayList:适用于 90% 的常规场景(读多写少、内存敏感)
  • 慎用 LinkedList:仅在需要频繁头尾操作或实现双端队列时选用
  • 线程安全场景 :根据写频率选择 CopyOnWriteArrayList 或同步包装类
相关推荐
意疏4 分钟前
浙江大学PTA程序设计C语言基础编程练习题6-10
c语言·开发语言
AI必将改变世界9 分钟前
【软考系统架构设计师备考笔记5】 - 专业英语
java·开发语言·人工智能·笔记·系统架构·英语
_祝你今天愉快12 分钟前
Java Lock
android·java·后端
listhi52013 分钟前
Python实现信号小波分解与重构
开发语言·python·重构
熊猫片沃子44 分钟前
mybatis 与mybatisplus 比较总结
java·后端·mybatis
骑驴看星星a1 小时前
层次分析法代码笔记
开发语言·笔记·python·numpy
Elastic 中国社区官方博客1 小时前
升级 Elasticsearch 到新的 AWS Java SDK
java·大数据·elasticsearch·搜索引擎·云计算·全文检索·aws
枣伊吕波2 小时前
十一、请求响应-请求:简单参数和实体参数(简单实体参数与复杂实体参数)
java·spring boot·后端
苇柠2 小时前
SpringMVC基础
java·后端·spring
xingzizhanlan2 小时前
apache-tomcat-11.0.9安装及环境变量配置
java·tomcat·apache