Java集合框架全解析
约 1538 字大约 5 分钟
javacollections
2025-03-01
概述
Java集合框架(Java Collections Framework,JCF)是 java.util 包中一组统一的接口和实现类,提供了对数据集合的存储、检索、操作和通信的标准架构。它是Java中最核心的基础设施之一,几乎所有Java程序都依赖它来管理对象集合。
集合框架层次结构
核心接口详解
Collection接口
Collection 是集合框架的根接口,定义了所有集合的基本操作:
public interface Collection<E> extends Iterable<E> {
int size();
boolean isEmpty();
boolean contains(Object o);
Iterator<E> iterator();
Object[] toArray();
boolean add(E e);
boolean remove(Object o);
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c);
void clear();
// Java 8+
default Stream<E> stream() { ... }
default Stream<E> parallelStream() { ... }
}List — 有序可重复
List 维护元素插入顺序,允许重复元素,支持按索引访问。
// ArrayList — 动态数组实现
List<String> arrayList = new ArrayList<>();
arrayList.add("alpha");
arrayList.add("beta");
arrayList.get(0); // O(1) 随机访问
// LinkedList — 双向链表实现
List<String> linkedList = new LinkedList<>();
linkedList.add("alpha");
linkedList.addFirst("zero"); // O(1) 头部插入
// 不可变List(Java 9+)
List<String> immutable = List.of("a", "b", "c");Set — 无重复元素
Set 不允许重复元素,判重依赖 equals() 和 hashCode()。
// HashSet — 基于HashMap实现
Set<String> hashSet = new HashSet<>();
hashSet.add("java");
hashSet.add("java"); // 不会重复添加
// 遍历顺序不确定
// LinkedHashSet — 维护插入顺序
Set<String> linked = new LinkedHashSet<>();
// TreeSet — 基于红黑树,元素自然排序
Set<Integer> treeSet = new TreeSet<>();
treeSet.add(3);
treeSet.add(1);
treeSet.add(2);
// 遍历顺序: 1, 2, 3Queue 与 Deque
// PriorityQueue — 基于堆的优先队列
Queue<Integer> pq = new PriorityQueue<>();
pq.offer(5);
pq.offer(1);
pq.offer(3);
pq.poll(); // 返回 1(最小元素)
// ArrayDeque — 基于循环数组的双端队列
Deque<String> deque = new ArrayDeque<>();
deque.offerFirst("head");
deque.offerLast("tail");
// 替代Stack和LinkedList作为队列/栈使用Map — 键值映射
Map 不继承 Collection,它维护键值对映射关系。
Map<String, Integer> map = new HashMap<>();
map.put("java", 1);
map.put("python", 2);
// Java 8+ 增强方法
map.getOrDefault("go", 0);
map.putIfAbsent("java", 99);
map.computeIfAbsent("rust", k -> k.length());
map.merge("java", 1, Integer::sum);
// 遍历方式
map.forEach((key, value) -> System.out.println(key + "=" + value));
for (Map.Entry<String, Integer> entry : map.entrySet()) {
// entry.getKey(), entry.getValue()
}迭代模式
List<String> list = List.of("a", "b", "c", "d");
// 1. Iterator — 安全删除
Iterator<String> it = new ArrayList<>(list).iterator();
while (it.hasNext()) {
if (it.next().equals("b")) {
it.remove(); // 唯一安全的遍历中删除方式
}
}
// 2. for-each(编译后变成Iterator)
for (String s : list) {
System.out.println(s);
}
// 3. Stream API(Java 8+)
list.stream()
.filter(s -> s.compareTo("b") > 0)
.map(String::toUpperCase)
.forEach(System.out::println);
// 4. ListIterator — List专属双向迭代
ListIterator<String> lit = new ArrayList<>(list).listIterator(list.size());
while (lit.hasPrevious()) {
System.out.println(lit.previous()); // 反向遍历
}时间复杂度对比
| 操作 | ArrayList | LinkedList | HashSet | TreeSet | HashMap | TreeMap |
|---|---|---|---|---|---|---|
| 随机访问 get(i) | O(1) | O(n) | — | — | — | — |
| 查找 contains | O(n) | O(n) | O(1) | O(log n) | O(1) | O(log n) |
| 头部插入 | O(n) | O(1) | — | — | — | — |
| 尾部插入 | O(1)* | O(1) | O(1)* | O(log n) | O(1)* | O(log n) |
| 删除(按值) | O(n) | O(n) | O(1) | O(log n) | O(1) | O(log n) |
| 排序 | O(n log n) | O(n log n) | — | 天然有序 | — | 天然有序 |
*表示均摊复杂度,扩容时可能为 O(n)。
Collections工具类
List<Integer> list = new ArrayList<>(List.of(3, 1, 4, 1, 5));
// 排序
Collections.sort(list);
Collections.sort(list, Comparator.reverseOrder());
// 查找
int idx = Collections.binarySearch(list, 4); // 需先排序
int max = Collections.max(list);
int min = Collections.min(list);
int freq = Collections.frequency(list, 1); // 元素出现次数
// 操作
Collections.reverse(list);
Collections.shuffle(list);
Collections.swap(list, 0, 1);
Collections.fill(list, 0);
Collections.rotate(list, 2); // 循环右移2位
// 不可变包装
List<Integer> unmodifiable = Collections.unmodifiableList(list);
// unmodifiable.add(1); // 抛出 UnsupportedOperationException
// 同步包装
List<Integer> syncList = Collections.synchronizedList(list);线程安全方案
| 非线程安全 | 线程安全替代 | 特点 |
|---|---|---|
| ArrayList | CopyOnWriteArrayList | 写时复制,读无锁 |
| HashSet | CopyOnWriteArraySet / ConcurrentHashMap.newKeySet() | 写时复制 / CAS |
| HashMap | ConcurrentHashMap | 分段锁/CAS |
| TreeMap | ConcurrentSkipListMap | 跳表实现,无锁读 |
| LinkedList | ConcurrentLinkedDeque | CAS无锁队列 |
| PriorityQueue | PriorityBlockingQueue | 阻塞式优先队列 |
常见陷阱
1. ConcurrentModificationException
// 错误:for-each中直接修改集合
List<String> list = new ArrayList<>(List.of("a", "b", "c"));
for (String s : list) {
if (s.equals("b")) {
list.remove(s); // ConcurrentModificationException
}
}
// 正确:使用Iterator.remove() 或 removeIf()
list.removeIf(s -> s.equals("b"));2. Arrays.asList 返回的固定大小List
List<String> fixed = Arrays.asList("a", "b", "c");
// fixed.add("d"); // UnsupportedOperationException
// 正确做法:
List<String> mutable = new ArrayList<>(Arrays.asList("a", "b", "c"));3. hashCode/equals 约定
作为 HashSet 或 HashMap 的 key 的对象,必须同时正确重写 hashCode() 和 equals(),否则会出现"放进去却找不到"的问题。
public class User {
private String name;
private int age;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User u)) return false;
return age == u.age && Objects.equals(name, u.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}选型指南
总结
Java集合框架通过统一的接口体系和丰富的实现类,覆盖了几乎所有常见的数据结构需求。选择合适的集合类需要综合考虑:数据特性(有序/无序、是否重复)、操作特性(读多写少、随机访问)、并发需求以及内存开销。理解每种实现的底层结构和复杂度特征,是写出高性能Java代码的基础。
贡献者
更新日志
2026/3/14 13:09
查看所有更新日志
9f6c2-feat: organize wiki content and refresh site setup于