Java中的集合类有哪些?如何分类的?
2026年01月21日
一则或许对你有用的小广告
欢迎 加入小哈的星球 ,你将获得: 专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新开坑项目: 《Spring AI 项目实战(问答机器人、RAG 增强检索、联网搜索)》 正在持续爆肝中,基于
Spring AI + Spring Boot3.x + JDK 21..., 点击查看; - 《从零手撸:仿小红书(微服务架构)》 已完结,基于
Spring Cloud Alibaba + Spring Boot3.x + JDK 17..., 点击查看项目介绍; 演示链接: http://116.62.199.48:7070/; - 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/
面试考察点
面试官提出这个问题,主要想考察以下几个方面:
- 对 Java 集合框架整体架构的理解:你是否能从宏观上把握
Collection和Map两大核心接口及其子类体系,而不仅仅是背诵单个类的 API。 - 分类的逻辑与依据:你是否能清晰地说出分类的维度,例如按接口划分(
CollectionvsMap)、按数据结构划分(数组、链表、哈希表、树等)以及按线程安全划分。 - 对核心类特性的掌握:能否说出主流集合类(如
ArrayList、HashMap)的底层实现、特性及典型应用场景。面试官不仅想知道“是什么”,更想知道 “为什么选它” 和 “如何正确使用它”。 - 知识体系的完整性:是否能关联到迭代器(
Iterator)、工具类(Collections)、Java 8+ 的 Stream API 等周边知识,展现一个立体的知识图谱。
核心答案
Java 集合类主要包含两大顶级接口:Collection 和 Map。整个集合框架可以按照以下逻辑进行分类:
-
按接口层次分类:
Collection: 存储一组对象的单列集合。它有三个主要子接口:List: 有序、可重复 的集合,典型实现有ArrayList、LinkedList、Vector。Set: 无序、不可重复 的集合,典型实现有HashSet、LinkedHashSet、TreeSet。Queue: 队列,典型实现有LinkedList、PriorityQueue、ArrayDeque。
Map: 存储键值对(Key-Value)的双列集合。键不可重复。典型实现有HashMap、LinkedHashMap、TreeMap、Hashtable。
-
按底层数据结构/特性分类:
- 基于数组:
ArrayList、Vector、ArrayDeque、HashMap(Node数组 + 链表/红黑树)。 - 基于链表:
LinkedList、LinkedHashSet、LinkedHashMap。 - 基于哈希表:
HashSet、HashMap、Hashtable、LinkedHashMap。 - 基于红黑树:
TreeSet、TreeMap、HashMap(链表转化)。 - 基于堆:
PriorityQueue。
- 基于数组:
-
按线程安全性分类:
- 非线程安全(主流):
ArrayList、LinkedList、HashSet、HashMap等。性能更高。 - 线程安全(遗留或专用):
- 古老的同步类:
Vector、Hashtable。 Collections.synchronizedXxx()包装器。- JUC(
java.util.concurrent)包下的并发集合:ConcurrentHashMap、CopyOnWriteArrayList等,采用更高效的并发控制机制。
- 古老的同步类:
- 非线程安全(主流):
深度解析
1. 设计哲学:接口与实现分离
整个集合框架的精髓在于 “面向接口编程”。List、Set、Map 等接口定义了行为契约,而具体的实现类(如 ArrayList、HashSet)负责实现细节。这使得我们可以轻松地替换实现,而无需修改业务代码,极大地提高了代码的灵活性和可维护性。
2. 关键数据结构与实现解析
-
ArrayListvsLinkedList:ArrayList基于动态数组,支持O(1)的随机访问,但在中间插入/删除(需移动元素)是O(n)。默认初始容量为 10,扩容系数为 1.5 倍。
// 代码示例:展示 ArrayList 与 LinkedList 在不同操作上的性能考量 List<String> arrayList = new ArrayList<>(); // 适合频繁查询 List<String> linkedList = new LinkedList<>(); // 适合频繁在头尾插入/删除LinkedList基于双向链表,在任意位置插入/删除(已知位置)是O(1),但随机访问是O(n)。它同时实现了Deque接口,可作为栈或双端队列使用。- 最佳实践:
ArrayList是绝大多数情况下的默认选择,因为它对 CPU 缓存更友好,综合性能通常更好。除非有频繁在列表中间进行插入/删除操作的明确需求,否则优先使用ArrayList。
-
HashMap的工作原理:- 数据结构: JDK 8 以后,
HashMap采用 “数组 + 链表 + 红黑树” 结构。 - 插入流程:
- 根据键的
hashCode()计算哈希值,再通过扰动函数((h = key.hashCode()) ^ (h >>> 16))得到最终的哈希值hash。 - 使用
(n - 1) & hash确定元素在数组(桶)中的索引。 - 如果该位置为空,直接插入新节点。
- 如果不为空(哈希冲突),则依次比较哈希值和键(
equals)。若键相同,则更新值;若不同,则以链表形式存储在同一桶中。 - 当链表长度超过
TREEIFY_THRESHOLD(默认为 8)且数组容量 >=MIN_TREEIFY_CAPACITY(默认为 64)时,链表将转化为红黑树,以将查找性能从O(n)提升至O(log n)。
- 根据键的
- 扩容机制: 当元素数量超过
容量 * 负载因子(默认 0.75)时,数组会扩容为原来的 2 倍,并重新计算所有元素的位置(rehash)。这是一个相对耗时的操作。
- 数据结构: JDK 8 以后,
3. 实际应用与选择策略
- 需要快速访问元素? 选
ArrayList或HashMap(通过键访问)。 - 需要元素有序?
- 插入顺序:
LinkedHashSet/LinkedHashMap。 - 自然顺序或自定义顺序:
TreeSet/TreeMap。
- 插入顺序:
- 需要保证元素唯一? 选
Set接口下的实现。 - 多线程环境? 绝不直接使用非线程安全的集合。优先考虑
ConcurrentHashMap、CopyOnWriteArrayList等 JUC 集合,它们比synchronized包装器性能更好。
4. 常见误区
- 滥用
ArrayList: 在需要频繁删除或前端插入的场景下仍坚持使用ArrayList,导致性能低下。 - 在多线程环境中直接使用
HashMap: 这会导致数据不一致或程序崩溃,必须使用并发集合或进行外部同步。 - 混淆
Set和Map的“唯一性”:Set的 “唯一性” 由元素的equals()和hashCode()保证;Map的 “唯一性” 仅针对键。 - 不了解
Iterator的fail-fast机制: 在使用迭代器遍历集合时,如果直接调用集合的remove方法修改集合,会抛出ConcurrentModificationException。正确的做法是使用迭代器的remove方法。
总结
Java 集合框架的核心在于以 Collection 和 Map 为根的两大接口体系,其分类可从接口层次、数据结构及线程安全三个维度理解。选择集合类的黄金法则是:根据你的核心业务需求(顺序、唯一性、访问模式、线程环境)来选择最匹配数据结构的实现,理解其底层原理是进行高效、正确编码的基础。