Java 集合框架详解(Java Collections Framework)
Java 集合框架(JCF)是 Java SE 中最核心的部分之一,位于 java.util 包下。它提供了一套统一的接口、抽象类和实现类,用于存储、管理和操作对象的集合(如列表、集合、映射等)。集合框架的核心目标是:高效、类型安全、易扩展。
本文将从基础到高级,系统详解集合框架,包括架构、核心接口/类、常用方法、线程安全、性能分析、源码要点、常见问题及最佳实践。基于 Java 17+(2026 主流版本)的视角,结合实际开发经验。
一、集合框架整体架构
集合框架分为两大体系:
- Collection 接口:单值集合(元素是单个对象)。
- 子接口:List(有序、可重复)、Set(无序、不重复)、Queue(队列)、Deque(双端队列)。
- Map 接口:键值对集合(key-value pairs,不继承 Collection)。
抽象类(如 AbstractList、AbstractSet)提供骨架实现,方便自定义扩展。
核心类图简述(文字版):
Collection (接口)
├── List (接口)
│ ├── ArrayList
│ ├── LinkedList
│ └── Vector (遗留)
├── Set (接口)
│ ├── HashSet
│ ├── LinkedHashSet
│ └── TreeSet (SortedSet/NavigableSet)
├── Queue (接口)
│ ├── PriorityQueue
│ └── ArrayDeque (Deque 接口实现)
└── Map (接口)
├── HashMap
├── LinkedHashMap
├── TreeMap (SortedMap/NavigableMap)
└── Hashtable (遗留)
- 辅助类:Collections(工具类,提供排序、同步等)、Arrays(数组工具)。
二、核心接口与实现类详解
1. List 接口(有序、可重复)
- 特点:支持索引访问、允许重复元素。
- 常用实现:
- ArrayList(首选):底层动态数组(Object[]),随机访问 O(1),扩容机制(1.5 倍增长)。
- LinkedList:底层双向链表,支持 Queue/Deque 接口,头尾操作 O(1),随机访问 O(n)。
- Vector:类似 ArrayList 但线程安全(synchronized),性能差,已过时。
2. Set 接口(无序、不重复)
- 特点:不允许重复(equals 判断),无索引。
- 常用实现:
- HashSet:底层 HashMap(key 存元素),O(1) 平均操作。
- LinkedHashSet:HashSet + 双向链表,保持插入顺序。
- TreeSet:底层红黑树(TreeMap),自动排序,支持 NavigableSet 接口(ceiling/floor 等)。
3. Queue 接口(先进先出 FIFO)
- 特点:用于任务调度、缓冲。
- 常用实现:
- PriorityQueue:底层堆(数组),按优先级出队 O(log n)。
- ArrayDeque:底层循环数组,双端队列,性能优于 LinkedList。
4. Map 接口(键值对)
- 特点:key 唯一(equals + hashCode),value 可重复。
- 常用实现:
- HashMap(首选):JDK8+ 数组 + 链表 + 红黑树(链表 >8 转树),负载因子 0.75。
- LinkedHashMap:HashMap + 双向链表,支持插入/访问顺序(LRU 缓存)。
- TreeMap:底层红黑树,按 key 排序,支持 NavigableMap(subMap 等)。
- Hashtable:线程安全版 HashMap,已过时。
Java 9+ 新增:不可变集合,如 List.of()、Set.of()、Map.of(),用于快速创建只读集合。
三、常用方法汇总(以 Collection 和 Map 为例)
Collection 接口方法
| 方法类别 | 示例方法 | 描述 |
|---|---|---|
| 添加 | add(E e), addAll(Collection c) | 添加元素/集合 |
| 删除 | remove(Object o), clear() | 删除元素/清空 |
| 查询 | contains(Object o), size(), isEmpty() | 检查包含/大小/空 |
| 遍历 | iterator(), forEach(Consumer) | 迭代器/函数式遍历(Java 8+) |
| 转换 | toArray() | 转数组 |
Map 接口方法
| 方法类别 | 示例方法 | 描述 |
|---|---|---|
| 添加/修改 | put(K key, V value), putAll(Map m) | 插入/覆盖键值对 |
| 删除 | remove(Object key), clear() | 删除键/清空 |
| 查询 | get(Object key), containsKey(K key) | 获取值/检查键 |
| 遍历 | keySet(), values(), entrySet() | 获取键集/值集/键值对集 |
| Java 8+ 新增 | computeIfAbsent, merge | 函数式操作(如默认值) |
示例代码(ArrayList + HashMap):
import java.util.*;
public class CollectionDemo {
public static void main(String[] args) {
// List 示例
List<String> list = new ArrayList<>();
list.add("apple");
list.add("banana");
list.add(1, "orange"); // 插入到索引1
System.out.println(list.get(0)); // apple
// Map 示例
Map<Integer, String> map = new HashMap<>();
map.put(1, "one");
map.put(2, "two");
System.out.println(map.get(1)); // one
// 遍历
map.forEach((k, v) -> System.out.println(k + ": " + v));
}
}
四、线程安全与并发集合
标准集合(如 ArrayList、HashMap)非线程安全,多线程下可能 ConcurrentModificationException。
- 遗留安全类:Vector、Hashtable(synchronized,全同步,性能低)。
- 现代推荐(java.util.concurrent 包):
- ConcurrentHashMap:分段锁 + CAS,读无锁,高并发首选。
- CopyOnWriteArrayList:写时复制,读无锁,适合读多写少。
- ConcurrentLinkedQueue:无锁队列,CAS 实现。
- 同步包装:Collections.synchronizedList(list),但性能不如并发包。
示例:
Map<String, String> safeMap = new ConcurrentHashMap<>();
safeMap.putIfAbsent("key", "value"); // 原子操作
五、性能分析与选择指南
性能对比表(平均复杂度)
| 集合类型 | 添加 | 删除 | 查询 | 遍历 | 空间开销 | 适用场景 |
|---|---|---|---|---|---|---|
| ArrayList | O(1) 摊销 | O(n) | O(1) | O(n) | 中等 | 随机访问、尾部操作 |
| LinkedList | O(1) | O(1) | O(n) | O(n) | 高(节点) | 频繁插入/删除 |
| HashSet/Map | O(1) | O(1) | O(1) | O(n) | 中等 | 快速查找、去重 |
| TreeSet/Map | O(log n) | O(log n) | O(log n) | O(n) | 中等 | 排序、范围查询 |
| PriorityQueue | O(log n) | O(log n) | O(1) peek | O(n) | 中等 | 优先级调度 |
- HashMap 源码要点:hash = key.hashCode() ^ (h >>> 16),链表转树阈值 8,树转链表阈值 6。
- 选择决策:
- 列表:99% 用 ArrayList,除非频繁头操作用 LinkedList/ArrayDeque。
- 集合:去重用 HashSet,需要顺序用 LinkedHashSet,排序用 TreeSet。
- 映射:普通用 HashMap,顺序用 LinkedHashMap,排序用 TreeMap。
- 并发:一律 ConcurrentXXX。
六、常见问题与最佳实践
常见问题
- ConcurrentModificationException:遍历时修改集合。解决:用 Iterator.remove() 或 CopyOnWrite。
- Null 值:HashMap 允许 null key/value,TreeMap 不允许 null key。
- 扩容开销:ArrayList 默认容量 10,扩容 1.5 倍。建议预估大小:
new ArrayList<>(100)。 - equals 与 hashCode:自定义类做 key/set 元素,必须重写(否则不唯一)。
- 不可变集合:Java 9+ 用 List.of(),避免意外修改。
最佳实践(2026 主流)
- 接口编程:
List<T> list = new ArrayList<>();(泛型 + 菱形运算符)。 - 函数式:用 stream() 处理,如
list.stream().filter(x -> x > 0).collect(Collectors.toList());。 - 大集合:用 Guava 或 Apache Commons 扩展(如 Multimap)。
- 内存优化:大 Map 用 LinkedHashMap + removeEldestEntry 实现 LRU。
- 避免遗留:别用 Vector/Hashtable,用并发包代替。
- 测试:用 JUnit 测试集合行为,尤其是自定义 equals/hashCode。
七、扩展与高级主题
- Java 8+ 增强:default 方法(如 Map.getOrDefault)、Stream API。
- 自定义集合:继承 AbstractList 等,实现最小方法。
- 序列化:集合实现 Serializable,但注意 transient 字段。
- 与数组:Arrays.asList() 转 List,但固定大小。
集合框架是 Java 开发的基石,熟练掌握能显著提升代码效率和质量。如果想深入某个类源码(如 HashMap 的 resize)、具体示例代码,或与 Kotlin/Scala 集合对比,继续问我~