Java 常用集合底层原理全解:数据结构、核心区别与面试考点完整梳理

作为 Java 开发者,集合框架是日常开发中最高频使用的基础工具,也是 Java 面试中 100% 覆盖的核心考点。很多开发者能够熟练调用集合 API,却对底层数据结构、实现逻辑一知半解,导致选型出错、踩性能坑,面试时也只能答出表面特性,讲不清设计逻辑。

本文系统梳理 Java 中所有主流常用集合,从底层数据结构、核心实现原理、横向性能对比、高频面试考点四个维度全面拆解,覆盖普通集合与并发集合,包含 List、Set、Map、队列 / 双端队列四大分支,补足优先级队列、跳表集合、写时复制集合、阻塞队列等易被忽略的核心内容,形成完整的集合知识体系。

一、Java 集合框架全景与核心数据结构总览

Java 集合本质是「经典数据结构的工程化实现」,每一种集合对应一种或多种数据结构,在时间、空间、功能、线程安全之间做不同的工程权衡。

1. 集合家族完整图谱

1. 集合家族完整图谱

复制代码
java.util.Collection(单元素集合)
├── List  有序、可重复、支持索引访问
│   ├── ArrayList              动态数组
│   ├── LinkedList             双向链表
│   ├── Vector                 同步动态数组(遗留类)
│   └── CopyOnWriteArrayList   写时复制动态数组(并发)
├── Set   无序、元素唯一
│   ├── HashSet                哈希表(基于HashMap)
│   ├── LinkedHashSet          哈希表+双向链表(基于LinkedHashMap)
│   ├── TreeSet                红黑树(基于TreeMap)
│   ├── CopyOnWriteArraySet    写时复制数组(并发)
│   └── ConcurrentSkipListSet  跳表(并发有序)
└── Queue / Deque  队列/双端队列
    ├── ArrayDeque             循环数组(双端队列)
    ├── PriorityQueue          二叉堆(优先级队列)
    ├── ArrayBlockingQueue     数组+单锁(有界阻塞队列)
    ├── LinkedBlockingQueue    链表+双锁(阻塞队列)
    ├── SynchronousQueue       无缓冲同步队列
    └── ConcurrentLinkedQueue  链表+CAS(无锁非阻塞队列)

java.util.Map(键值对集合)
├── HashMap                    数组+链表+红黑树
├── LinkedHashMap              HashMap + 双向链表
├── TreeMap                    红黑树(有序)
├── Hashtable                  哈希表+全表锁(遗留类)
├── ConcurrentHashMap          CAS + synchronized 细粒度锁
└── ConcurrentSkipListMap      跳表(并发有序)

2. 核心数据结构对照表

所有集合的性能差异,本质上都是底层数据结构的差异。

数据结构 核心特点 代表集合 平均时间复杂度 空间特性
动态数组 连续内存、支持随机访问 ArrayList、Vector 查 O (1)、尾增 O (1)、中间增删 O (n) 有预留空间,扩容有性能损耗
双向链表 节点离散、首尾操作快 LinkedList 首尾增删 O (1)、查询 O (n) 每个节点额外存储前后指针
循环数组 头尾指针、双端操作快 ArrayDeque 首尾增删 O (1)、查询 O (n) 容量始终为 2 的幂
哈希表 哈希映射、快速查找 HashMap、HashSet 平均 O (1),极端 O (n) 加载因子 0.75,空间换时间
红黑树 自平衡二叉搜索树 TreeMap、TreeSet 增删查均为 O (logn) 节点存储颜色、父子节点指针
二叉堆 完全二叉树、数组实现 PriorityQueue 增 O (logn)、取最值 O (1) 数组存储,空间利用率高
跳表 多层索引、有序查找 ConcurrentSkipListMap 平均 O (logn) 多层索引,空间开销略大
写时复制 修改时复制副本,读写分离 CopyOnWriteArrayList 读 O (1)、写 O (n) 写操作复制全量数组,内存开销

二、List 集合:有序、可重复

List 的核心特征是元素按插入顺序存储、允许重复、支持按索引随机访问,是日常开发中使用最频繁的集合分支。

1. ArrayList

底层数据结构

Object 类型的动态数组,核心字段:

  • Object[] elementData:存储元素的数组缓冲区
  • size:集合中实际存储的元素个数
  • modCount:结构修改次数,用于 fail-fast 并发修改校验
核心实现原理
  1. 初始化策略 :JDK1.8 开始采用懒加载,无参构造方法仅创建一个空数组,第一次执行add()时才真正初始化为容量 10 的数组
  2. 扩容机制 :元素数量超过数组容量时触发扩容,新容量 = 旧容量 + 旧容量 >> 1(即扩容为原来的 1.5 倍),通过Arrays.copyOf()批量复制元素到新数组
  3. 随机访问:通过数组下标直接定位元素,时间复杂度 O (1)
  4. 中间增删 :需要通过System.arraycopy()批量移动后续元素,时间复杂度 O (n)
优缺点与适用场景
  • 优势:随机访问极快,内存连续 CPU 缓存友好,内存开销小
  • 劣势:中间增删性能差,扩容有一次性性能损耗
  • 适用场景:绝大多数业务场景的首选,适合读多写少、增删主要在尾部的场景

2. LinkedList

底层数据结构

双向链表 ,每个元素是内部类Node<E>节点:

java 复制代码
private static class Node<E> {
    E item;
    Node<E> next; // 后继指针
    Node<E> prev; // 前驱指针
}

集合同时持有first头指针和last尾指针。

核心实现原理
  1. 首尾增删:仅需修改相邻节点的指针,时间复杂度 O (1)
  2. 指定位置操作:会根据索引位置选择从头或从尾遍历定位节点,时间复杂度 O (n)
  3. 随机访问:必须遍历链表,性能极差
  4. 无扩容问题:节点按需创建销毁,不需要预留空间,理论上容量无上限
常见误区

很多人认为 LinkedList 中间插入性能优于 ArrayList,实际上并非如此:中间插入前需要先遍历定位节点,这一步已经是 O (n) 的开销,仅在「已经持有目标节点引用」的场景下,插入性能才优于 ArrayList。

优缺点与适用场景
  • 优势:首尾增删无扩容损耗,理论容量无上限
  • 劣势:随机访问极慢,节点指针内存开销大,CPU 缓存不友好
  • 适用场景:仅在频繁头尾增删、完全不需要随机访问的场景使用;实现栈 / 队列时优先选择 ArrayDeque 而非 LinkedList

3. Vector

底层数据结构

与 ArrayList 完全一致,底层也是动态 Object 数组

核心实现原理
  • 几乎所有 public 方法都加了synchronized修饰,通过锁整个集合对象实现线程安全
  • 默认扩容为原来的 2 倍,可通过构造参数指定容量增长步长
为什么不推荐使用
  • 锁粒度太粗,所有方法串行执行,并发性能极低
  • 属于 JDK1.0 的遗留类,设计老旧,官方早已不推荐
  • 即使加锁,复合操作(如先检查后添加)也不是原子的,仍然存在并发问题

4. CopyOnWriteArrayList(并发)

底层数据结构

写时复制的动态数组 ,底层数组用volatile修饰,保证数组引用的内存可见性。

核心实现原理:写时复制(COW)
  • 读操作:直接读取原数组,完全无锁,性能极高
  • 写操作:加独占锁,复制一份全新的数组,在新数组上执行修改,修改完成后将数组引用指向新数组,最后释放锁
  • 迭代器基于创建时的数组快照遍历,属于 fail-safe 机制,不会抛出并发修改异常
优缺点与适用场景
  • 优势:读操作完全无锁,并发读性能极高,线程安全
  • 劣势:写操作开销大,每次修改都要复制整个数组;内存占用高;数据是弱一致性的,读不到刚写入的数据
  • 适用场景:读多写少的并发场景,如配置列表、黑白名单等更新不频繁的数据

List 四大实现完整对比

特性 ArrayList LinkedList Vector CopyOnWriteArrayList
底层结构 动态数组 双向链表 动态数组 写时复制动态数组
随机访问 O (1),极快 O (n),极慢 O (1),极快 O (1),极快
尾部增删 O(1) O(1) O(1) O (n),需复制数组
中间增删 O (n),移动元素 O (n),遍历定位 O(n) O(n)
线程安全 不安全,fail-fast 不安全,fail-fast 安全,全表锁 安全,写时复制
扩容机制 1.5 倍扩容 无扩容 2 倍扩容 每次写都扩容
内存占用 小,有预留空间 大,指针开销高 大,写时双份数组
数据一致性 强一致 强一致 强一致 弱一致
推荐指数 ⭐⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐

三、Set 集合:无序、元素唯一

Set 的核心特征是元素不重复,所有 Set 实现本质上都是对应 Map 的「马甲」------ 仅使用 Map 的 key 存储元素,value 是一个固定的静态常量对象。

1. HashSet

底层数据结构

完全基于HashMap 实现,所有元素作为 HashMap 的 key 存入,value 是固定的静态对象PRESENT = new Object()

去重原理

完全依赖 HashMap 的 key 去重逻辑:

  1. 计算元素的 hashCode 定位数组下标
  2. 下标位置已有元素则遍历链表 / 红黑树,通过equals()比对
  3. key 相同则覆盖 value(无实际意义),key 不同则新增节点

自定义对象作为 HashSet 元素时,必须同时重写hashCode()equals(),否则会出现元素重复、查询不到的问题。

特性与适用场景
  • 无序:不保证遍历顺序,也不保证顺序随时间不变
  • 允许存入 1 个 null 元素
  • 增删查平均 O (1),是性能最好的 Set 实现
  • 通用去重场景的首选

2. LinkedHashSet

底层数据结构

继承自 HashSet,底层基于LinkedHashMap,在哈希表基础上额外维护一条贯穿所有节点的双向链表,用于记录元素的插入顺序。

特性与适用场景
  • 插入有序:遍历顺序与元素插入顺序一致
  • 性能略低于 HashSet,因为需要额外维护双向链表
  • 允许 1 个 null 元素
  • 适用于需要去重同时保留插入顺序的场景

3. TreeSet

底层数据结构

基于**TreeMap(红黑树)**实现,元素作为 TreeMap 的 key 存储。

去重与排序原理
  • 不依赖 hashCode/equals,而是通过Comparable.compareTo()Comparator.compare()返回 0 判断元素重复
  • 元素按自然排序或自定义比较器排序,而非插入顺序
  • 不允许 null 元素(无法比较大小)
特性与适用场景
  • 排序有序,支持范围查询(获取大于 / 小于某个值的元素)
  • 增删查均为 O (logn),性能低于 HashSet
  • 适用于需要去重同时对元素排序、需要范围查询的场景

4. CopyOnWriteArraySet(并发)

底层数据结构

基于CopyOnWriteArrayList实现,本质是封装了一层去重逻辑的写时复制数组。

特性与适用场景
  • 线程安全,读多写少场景适用
  • 插入时需要遍历数组检查重复,性能较差
  • 弱一致性,迭代器基于快照
  • 适用于并发环境下、数据量小、更新不频繁的去重场景

5. ConcurrentSkipListSet(并发)

底层数据结构

基于**ConcurrentSkipListMap(跳表)**实现,是并发版本的有序 Set。

特性与适用场景
  • 线程安全,基于跳表的无锁并发设计
  • 排序有序,支持并发场景下的范围查询
  • 增删查平均 O (logn)
  • 适用于高并发环境下需要有序去重的场景

Set 五大实现完整对比

特性 HashSet LinkedHashSet TreeSet CopyOnWriteArraySet ConcurrentSkipListSet
底层结构 HashMap LinkedHashMap TreeMap(红黑树) CopyOnWriteArrayList ConcurrentSkipListMap
顺序性 无序 插入有序 排序有序 插入有序 排序有序
去重依据 hashCode+equals hashCode+equals compareTo/compare equals compareTo/compare
null 支持 1 个 null 1 个 null 不支持 支持 不支持
线程安全 不安全 不安全 不安全 安全 安全
平均时间复杂度 O(1) O(1) O(logn) 写 O (n),读 O (1) O(logn)
性能 最好 略低 中等 写极慢,读极快 较好
适用场景 通用去重 去重 + 保插入顺序 去重 + 排序 并发读多写少 并发有序去重

四、Map 集合:键值对存储

1. HashMap

底层数据结构

JDK1.8 后为数组 + 链表 + 红黑树,JDK1.7 为数组 + 单向链表。

核心特性总结
  • 初始容量 16,加载因子 0.75,扩容为原来的 2 倍
  • 数组长度始终为 2 的幂,通过位运算替代取模计算下标
  • 链表长度≥8 且数组容量≥64 时转红黑树,树节点≤6 时退回链表
  • 线程不安全,并发扩容会出现数据覆盖等问题
  • 通用键值对存储的首选,详细原理可参考 HashMap 专题文章

2. LinkedHashMap

底层数据结构

继承自 HashMap,在其基础上给每个节点增加了beforeafter指针,形成一条贯穿所有节点的双向链表,用于维护访问顺序。

两种顺序模式
  1. 插入顺序(默认)accessOrder = false,遍历顺序与 key 的插入顺序一致,重新插入已存在的 key 不改变顺序
  2. 访问顺序accessOrder = true,每次get/put访问元素后,会将该元素移到双向链表尾部,实现「最近访问的在后面」
经典应用:LRU 缓存

基于访问顺序模式,只需重写removeEldestEntry()方法即可实现简易 LRU 缓存:

java 复制代码
public class LRUCache<K,V> extends LinkedHashMap<K,V> {
    private final int capacity;
    public LRUCache(int capacity) {
        super(capacity, 0.75f, true); // 开启访问顺序模式
        this.capacity = capacity;
    }
    // 超过容量时淘汰最久未访问的头部元素
    @Override
    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        return size() > capacity;
    }
}

3. TreeMap

底层数据结构

红黑树(自平衡二叉搜索树),每个节点包含 key、value、左右子节点、父节点、颜色标识。

核心特性
  • 排序有序:key 按自然排序或自定义比较器排序
  • key 约束:必须实现Comparable接口或构造时传入Comparator;不允许 null key
  • 高级功能:支持范围查询subMap()/headMap()/tailMap(),支持获取最大 / 最小 key
  • 增删查均为 O (logn),通过旋转、变色维持树的平衡
  • 适用于需要对 key 排序、需要范围查询的场景

4. Hashtable

底层数据结构

数组 + 单向链表,结构与 JDK1.7 的 HashMap 类似。

核心特性
  • 几乎所有方法都加synchronized,锁整个 Hashtable 对象,线程安全但性能极低
  • key 和 value 都不允许为 null
  • 默认容量 11,扩容为 2 倍 + 1
  • JDK1.0 遗留类,官方早已不推荐使用

5. ConcurrentHashMap

底层数据结构
  • JDK1.7:分段锁(Segment 数组 + 哈希表数组 + 链表)
  • JDK1.8:数组 + 链表 + 红黑树,采用 CAS + synchronized 细粒度锁
核心特性总结
  • JDK1.8 锁粒度细化到单个桶,空桶用 CAS 插入,有元素的桶锁头节点
  • 支持多线程协助扩容,大幅提升扩容效率
  • 采用 baseCount + CounterCell 分散计数,size () 为弱一致近似值
  • key 和 value 都不允许为 null
  • 并发键值对存储的首选,详细原理可参考 ConcurrentHashMap 专题文章

6. ConcurrentSkipListMap(并发有序)

底层数据结构

跳表(Skip List),一种多层索引的有序链表结构:

  • 最底层是完整的有序链表,包含所有数据节点
  • 上层是下层的索引层,节点数量逐层减少
  • 查询时从顶层索引开始,逐层向下定位,跳过大量节点,达到类似二分查找的效率
为什么并发有序 Map 用跳表不用红黑树?

红黑树的插入删除需要旋转、变色,影响范围大,并发加锁复杂;而跳表的修改仅影响局部相邻节点,更容易实现细粒度并发控制,且范围查询更方便。

特性与适用场景
  • 线程安全,并发性能优于Collections.synchronizedSortedMap
  • key 排序有序,支持并发场景下的范围查询
  • 增删查平均 O (logn)
  • key 不允许为 null
  • 适用于高并发环境下需要有序键值对、范围查询的场景

Map 六大实现完整对比

特性 HashMap LinkedHashMap TreeMap Hashtable ConcurrentHashMap ConcurrentSkipListMap
底层结构 数组 + 链表 + 红黑树 HashMap + 双向链表 红黑树 数组 + 链表 CAS+synchronized + 红黑树 跳表
顺序性 无序 插入 / 访问有序 排序有序 无序 无序 排序有序
null 键值 1 个 null 键,多 null 值 同 HashMap key 不能为 null 都不能为 null 都不能为 null key 不能为 null
线程安全 不安全 不安全 不安全 安全,全表锁 安全,细粒度锁 安全,跳表并发
平均时间复杂度 O(1) O(1) O(logn) O(1) O(1) O(logn)
性能 单线程最好 略低 中等 最差 高并发下最优 较好
适用场景 通用首选 保序、LRU 缓存 排序、范围查询 不推荐 并发通用 并发有序 + 范围查询

五、Queue / Deque 集合:队列与栈

这部分是集合体系中最容易被忽略但面试高频的分支,包含普通队列、双端队列、优先级队列、阻塞队列、非阻塞并发队列等多种实现。

1. ArrayDeque

底层数据结构

循环数组,核心字段:

  • Object[] elements:存储元素的数组,容量始终是 2 的幂
  • head:头指针,指向队首元素的下标
  • tail:尾指针,指向队尾下一个空位的下标
核心实现原理
  • 通过头尾指针的移动实现元素增删,不需要移动数组元素
  • 头尾指针越过数组边界时自动绕回另一端,形成循环
  • 容量不足时自动扩容为原来的 2 倍
  • 同时实现Deque接口,支持双端操作,既可以当队列也可以当栈
为什么比 LinkedList 快?
  • 数组内存连续,CPU 缓存友好
  • 首尾增删仅需移动指针,不需要创建销毁节点对象
  • 没有节点对象的额外内存开销
适用场景

实现栈、双端队列、普通队列的首选,Java 官方推荐替代古老的 Stack 类和 LinkedList。

2. PriorityQueue 优先级队列

底层数据结构

二叉堆(完全二叉树,用数组存储),默认是小顶堆(堆顶元素最小)。

完全二叉树的数组映射规则:

  • 下标为i的节点,左孩子下标为2*i+1,右孩子为2*i+2
  • 父节点下标为(i-1) / 2
核心实现原理
  1. 入队(offer) :元素加到数组末尾,执行上浮操作:与父节点比较,比父节点小就交换位置,直到满足堆的性质
  2. 出队(poll) :取出堆顶元素,将数组最后一个元素移到堆顶,执行下沉操作:与左右孩子比较,和较小的孩子交换,直到满足堆的性质
  3. 排序依据 :元素实现Comparable接口,或构造时传入自定义Comparator
  4. 扩容机制:容量小于 64 时扩容 2 倍;大于等于 64 时扩容 1.5 倍
特性与适用场景
  • 不保证整体有序,仅保证堆顶是最值
  • 不支持按索引随机访问
  • 线程不安全,不允许 null 元素
  • 适用于 TopK 问题、任务调度、定时器等需要按优先级处理元素的场景

3. 阻塞队列家族(并发)

阻塞队列是生产者 - 消费者模式的核心组件,支持「队满时入队阻塞、队空时出队阻塞」。

ArrayBlockingQueue
  • 底层:数组 + 一把 ReentrantLock + 两个 Condition(notEmpty、notFull)
  • 特性:有界队列,必须指定容量,初始化后不可扩容;单锁设计,入队和出队不能同时进行
  • 适用:容量固定的生产者消费者场景
LinkedBlockingQueue
  • 底层:单向链表 + 两把锁(takeLock、putLock)
  • 特性:可配置有界 / 无界,默认近似无界(Integer.MAX_VALUE);双锁设计,入队和出队互不阻塞,并发性能更高
  • 适用:绝大多数生产者消费者场景,性能优于 ArrayBlockingQueue
SynchronousQueue
  • 底层:无缓冲队列,不存储任何元素
  • 特性:入队必须等待另一个线程来出队,出队必须等待另一个线程来入队,元素直接交接,不经过缓冲区
  • 适用:线程池 CachedThreadPool 的核心实现,适合任务直接交接的场景
PriorityBlockingQueue
  • 底层:二叉堆 + 一把锁,无界队列
  • 特性:并发版本的优先级队列,出队按优先级排序
  • 适用:并发环境下的优先级任务调度

4. ConcurrentLinkedQueue(非阻塞并发队列)

底层数据结构

单向链表 + CAS 无锁算法。

核心实现原理
  • 不使用锁,完全通过 CAS 操作实现并发安全
  • 无界队列,容量仅受内存限制
  • 采用延迟更新头尾节点的优化设计,减少 CAS 竞争次数
特性与适用场景
  • 非阻塞,高并发下性能优于阻塞队列
  • 不支持阻塞等待
  • size () 返回近似值,弱一致性
  • 适用于高并发下不需要阻塞等待的非阻塞队列场景

常用队列完整对比

队列实现 底层结构 有界 / 无界 线程安全 阻塞特性 排序特性 适用场景
ArrayDeque 循环数组 无界 不安全 不阻塞 插入有序 栈、双端队列,单线程
PriorityQueue 二叉堆 无界 不安全 不阻塞 优先级排序 优先级任务,单线程
ArrayBlockingQueue 数组 + 单锁 有界 安全 阻塞 插入有序 固定容量生产者消费者
LinkedBlockingQueue 链表 + 双锁 有界 / 无界 安全 阻塞 插入有序 通用生产者消费者
SynchronousQueue 无缓冲 0 容量 安全 阻塞 任务直接交接
PriorityBlockingQueue 二叉堆 + 锁 无界 安全 阻塞 优先级排序 并发优先级任务
ConcurrentLinkedQueue 链表 + CAS 无界 安全 不阻塞 插入有序 高并发非阻塞队列

六、面试高频核心考点

1. ArrayList 和 LinkedList 的本质区别?

本质是数组和链表两种数据结构的差异

  • 内存布局:数组是连续内存,链表是离散节点
  • 访问性能:数组随机访问 O (1),链表必须遍历 O (n)
  • 增删性能:数组中间增删需要移动元素;链表仅需改指针,但需要先遍历定位
  • 缓存友好:数组连续内存 CPU 缓存命中率高,链表缓存不友好

绝大多数场景都应该用 ArrayList,仅在频繁头尾增删且极少随机访问时考虑 LinkedList;实现栈 / 队列优先选 ArrayDeque。

2. PriorityQueue 的底层原理是什么?如何保证有序?

PriorityQueue 底层是二叉堆(数组实现的完全二叉树),默认小顶堆。

  • 它不保证整体有序,仅保证堆顶元素是最值
  • 入队执行上浮操作,出队执行下沉操作,维持堆的性质
  • 想要得到全量有序结果,需要逐个 poll 出队

3. 写时复制(COW)的原理与优缺点?

原理:读操作直接读取原数组,完全无锁;写操作加独占锁,复制一份新数组,修改完成后替换数组引用。

  • 优点:读性能极高,线程安全,迭代不会抛出并发修改异常
  • 缺点:写操作开销大,内存占用高;数据弱一致性;写频繁时性能极差
  • 适用:读多写少、数据更新不频繁的场景

4. 跳表和红黑树有什么区别?为什么并发有序 Map 用跳表?

表格

维度 跳表 红黑树
数据结构 多层索引有序链表 自平衡二叉搜索树
查找效率 平均 O (logn) 稳定 O (logn)
实现复杂度 简单 复杂
范围查询 方便,直接遍历链表 麻烦,需要中序遍历
并发友好度 高,修改仅影响局部节点 低,旋转影响范围大

并发有序集合用跳表不用红黑树,核心原因是跳表修改仅影响局部节点,更容易实现细粒度并发控制,并发性能更好,且范围查询更便捷。

5. fail-fast 和 fail-safe 的区别?

  • fail-fast(快速失败) :普通非并发集合采用。迭代时维护expectedModCount,检测到集合结构被修改则立即抛出ConcurrentModificationException,目的是快速暴露并发修改问题。
  • fail-safe(安全失败):并发集合采用。迭代基于数据快照,不会抛出异常,但迭代器看不到最新数据,是弱一致性的。

6. 为什么不推荐 Vector 和 Hashtable?

  • 锁粒度太粗,全对象加锁,所有方法串行执行,并发性能极低
  • 属于 JDK1.0 遗留产物,设计老旧,官方早已不推荐
  • 即使加锁,复合操作也不是原子的,仍然存在并发问题
  • 有更优的替代方案:单线程用普通集合,并发场景用并发集合

七、集合选型最佳实践

  1. 普通列表存储:优先选 ArrayList,90% 以上场景的最优解
  2. 栈 / 双端队列:选 ArrayDeque,不要用 Stack 和 LinkedList
  3. 通用去重:优先选 HashSet,性能最好
  4. 去重 + 保插入顺序:选 LinkedHashSet
  5. 去重 + 排序 / 范围查询:选 TreeSet
  6. 普通键值对:优先选 HashMap
  7. 键值对 + 排序 / 范围查询:选 TreeMap
  8. 并发键值对:选 ConcurrentHashMap,绝对不用 Hashtable
  9. 并发有序键值对:选 ConcurrentSkipListMap
  10. 并发读多写少列表:选 CopyOnWriteArrayList
  11. 生产者消费者模式:优先选 LinkedBlockingQueue,固定容量选 ArrayBlockingQueue
  12. 优先级任务:单线程用 PriorityQueue,并发用 PriorityBlockingQueue

八、总结

Java 集合框架的选型,本质上是数据结构的选型。每一种集合都对应一种经典数据结构,有其擅长的场景和固有的短板。

理解底层数据结构,才能从本质上区分不同集合的差异,在合适的场景选对合适的工具,既保证性能,又能避开各种隐性坑点;面试时也能从原理层面讲清设计逻辑,而不只是背诵 API 和表面特性。

相关推荐
认真的酒窝2 小时前
自己动手开发编译器(十一)语义分析
java·开发语言
wbs_scy4 小时前
Linux C++ 高并发编程:线程池全链路深度解析,从原理到手撕实现
java·开发语言
JAVA面经实录9174 小时前
Linux 常用命令完整知识体系
java·linux·开发语言·汇编
Full Stack Developme5 小时前
Java LRU 与 LFU 算法及应用
java·开发语言·算法
疋瓞7 小时前
python和C++对比(1)_数据类型和数据结构
数据结构·c++·python
程序员老油条7 小时前
WSL2 + Docker Desktop:Windows 下的完美 Java 开发环境
java·windows·docker·wsl2
如此这般英俊8 小时前
手搓Claude Code-第六章 subagent
数据结构·人工智能·python·语言模型·自然语言处理
shushangyun_8 小时前
2026智能采购商城系统选型指南:如何引领企业数字化采购升级
java·大数据·数据库·人工智能·机器学习
她说..9 小时前
Java 默认值设置方式
java·开发语言·后端·springboot
学渣超9 小时前
记一次分布式事务数据不一致的排查之旅:从超时到索引,层层剥茧
java·后端·架构