Java 集合类全景介绍
面向前端开发者。如果你用 JS 的 Array、Set、Map、Object,这篇文章帮你一次性认清 Java 所有集合类。
目录
- [先看 JS:你已会的集合类型](#先看 JS:你已会的集合类型)
- [Java 集合框架全景图](#Java 集合框架全景图)
- List:有序可重复
- Set:无序不重复
- [Queue / Deque:队列与双端队列](#Queue / Deque:队列与双端队列)
- Map:键值对
- 线程安全集合
- 怎么选?决策速查表
- [与 JS 的终极对照表](#与 JS 的终极对照表)
1. 先看 JS:你已会的集合类型
// JS 里的集合就这几种
const arr = [1, 2, 3]; // ← 什么都能干:列表 + 队列 + 栈
const set = new Set([1, 2, 2]); // ← 去重
const map = new Map(); // ← 键值对
const obj = { a: 1, b: 2 }; // ← 也是键值对
Java 不一样------每种数据结构有专门的类,一个场景一个最优解。
| JS |
Java 对应 |
说明 |
Array(列表) |
ArrayList |
最常用,动态数组 |
Array(要用队列/栈) |
ArrayDeque / LinkedList |
Java 不会用一个类干所有事 |
Set |
HashSet / TreeSet |
去重集合 |
Map |
HashMap / TreeMap |
键值对 |
Object(字符串 key) |
HashMap<String, V> |
Java 没有字面量对象 |
2. Java 集合框架全景图
Iterable (接口)
│
Collection (接口)
/ | \
List Set Queue/Deque
│ │ │
┌────┴────┐ ┌──┴──┐ ┌──┴──┐
ArrayList LinkedList HashSet PriorityQueue
│ │
Vector LinkedHashSet
TreeSet
Map (独立体系)
/ | \
HashMap TreeMap Hashtable
│
LinkedHashMap
│
ConcurrentHashMap
记住:Collection 是单值集合,Map 是键值对,两条线不互相继承。
3. List:有序可重复
和 JS 的 Array 最像。有索引、可重复、有顺序。
3.1 ArrayList(⭐⭐⭐⭐⭐ 最常用)
List<String> list = new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("王五");
list.get(0); // "张三"
list.size(); // 3
list.remove(1); // 删除"李四"
| 特性 |
说明 |
| 底层 |
Object[] 动态数组 |
| 查询 |
O(1) --- 直接通过下标访问 |
| 插入/删除 |
O(n) --- 需要搬移后续元素 |
| 扩容 |
默认 10 → 1.5 倍扩容 |
| 适用 |
读多写少(查数据快) |
3.2 LinkedList
List<String> list = new LinkedList<>();
list.add("张三");
list.addFirst("队首"); // Deque 的方法
list.addLast("队尾");
| 特性 |
说明 |
| 底层 |
双向链表 |
| 查询 |
O(n) --- 需要从头遍历 |
| 插入/删除 |
O(1) --- 改指针即可(但定位到位置还是 O(n)) |
| 额外能力 |
实现了 Deque,可当队列/栈用 |
| 适用 |
频繁头尾增删;但大部分场景 ArrayList 更好(内存连续,CPU 缓存友好) |
3.3 Vector(⚠ 过时,不推荐)
// 和 ArrayList 几乎一样,但所有方法加了 synchronized
// JDK 1.0 的老古董,现在用 Collections.synchronizedList() 或 CopyOnWriteArrayList
List<String> vec = new Vector<>(); // ❌ 不推荐
3.4 ArrayList vs LinkedList 速查
|
ArrayList |
LinkedList |
| 底层 |
数组 |
双向链表 |
| get(i) |
O(1) ⭐ |
O(n) |
| add(E) |
O(1) 均摊 |
O(1) |
| add(0, E) |
O(n) |
O(1) ⭐ |
| 内存 |
连续,浪费少 |
每个节点额外存 prev/next 指针 |
| 用哪个? |
90% 选它 |
只在频繁头插时考虑 |
4. Set:无序不重复
和 JS 的 new Set() 一样------去重。
4.1 HashSet(⭐⭐⭐⭐⭐ 最常用)
Set<String> set = new HashSet<>();
set.add("Java");
set.add("Python");
set.add("Java"); // 重复,被忽略
set.size(); // 2
set.contains("Java"); // true
| 特性 |
说明 |
| 底层 |
就是 HashMap!(value 固定为 PRESENT 占位符) |
| 顺序 |
无序 |
| 复杂度 |
add/remove/contains 都是 O(1) |
| 去重依据 |
hashCode() + equals() |
4.2 LinkedHashSet
Set<String> set = new LinkedHashSet<>();
set.add("C");
set.add("A");
set.add("B");
// 遍历顺序:C → A → B(保持插入顺序)
| 特性 |
说明 |
| 底层 |
LinkedHashMap(HashSet + 双向链表维护顺序) |
| 顺序 |
保持插入顺序 |
| 代价 |
比 HashSet 多一点点内存 |
4.3 TreeSet
Set<Integer> set = new TreeSet<>();
set.add(5);
set.add(1);
set.add(3);
// 遍历顺序:1 → 3 → 5(自然排序)
| 特性 |
说明 |
| 底层 |
TreeMap(红黑树) |
| 顺序 |
自动排序(自然序或 Comparator) |
| 复杂度 |
O(log n) |
| 要求 |
元素必须实现 Comparable 或传 Comparator |
4.4 Set 速查
|
HashSet |
LinkedHashSet |
TreeSet |
| 顺序 |
无序 |
插入序 |
排序序 |
| 复杂度 |
O(1) |
O(1) |
O(log n) |
| 去重依据 |
hashCode + equals |
hashCode + equals |
compareTo / Comparator |
| 用哪个? |
只要去重 |
去重 + 保持顺序 |
去重 + 自动排序 |
5. Queue / Deque:队列与双端队列
5.1 Queue 接口方法
Queue<String> q = new LinkedList<>();
// 三组方法,每组两个:一个抛异常,一个返回特殊值
q.add("A"); // 入队,失败抛异常
q.offer("B"); // 入队,失败返回 false ← 推荐
q.remove(); // 出队,空队抛异常
q.poll(); // 出队,空队返回 null ← 推荐
q.element(); // 看队首,空队抛异常
q.peek(); // 看队首,空队返回 null ← 推荐
5.2 实现类
| 类 |
底层 |
场景 |
| LinkedList |
双向链表 |
实现了 List + Deque,既能当列表又能当队列 |
| PriorityQueue |
二叉堆 |
优先级队列---每次 poll 出最小/最大的元素 |
| ArrayDeque |
循环数组 |
⭐ 推荐---比 LinkedList 快,当栈/队列首选 |
5.3 ArrayDeque:栈和队列的最佳实践
// 当栈用(替代 Stack)
Deque<String> stack = new ArrayDeque<>();
stack.push("A"); // 压栈
stack.push("B");
stack.pop(); // "B"(后进先出)
// 当队列用
Deque<String> queue = new ArrayDeque<>();
queue.offer("A"); // 入队
queue.offer("B");
queue.poll(); // "A"(先进先出)
Java 官方推荐 用 ArrayDeque 代替 Stack(Stack 是 JDK 1.0 的过时类)。
6. Map:键值对
和 JS 的 Map / Object 对应。Java 中最常用的数据结构之一。
6.1 HashMap(⭐⭐⭐⭐⭐ 最常用)
Map<String, Integer> map = new HashMap<>();
map.put("张三", 95);
map.put("李四", 87);
map.get("张三"); // 95
map.containsKey("李四"); // true
map.remove("张三");
// 遍历
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
// Java 8+ Lambda
map.forEach((k, v) -> System.out.println(k + " = " + v));
| 特性 |
说明 |
| 底层 |
数组 + 链表 + 红黑树 |
| 顺序 |
无序 |
| get/put |
O(1) ~ O(log n) |
| null |
允许一个 null key,多个 null value |
| 线程安全 |
❌ |
| 深入原理 |
见 Java-HashMap原理详解.md |
6.2 LinkedHashMap
Map<String, Integer> map = new LinkedHashMap<>();
map.put("C", 3);
map.put("A", 1);
map.put("B", 2);
// 遍历顺序:C → A → B(保持插入顺序)
| 特性 |
说明 |
| 底层 |
HashMap + 双向链表 |
| 顺序 |
保持插入顺序(或 accessOrder=true 按访问顺序,实现 LRU) |
// LRU 缓存的经典实现
Map<String, Integer> lru = new LinkedHashMap<String, Integer>(16, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > 100; // 超过 100 条自动删除最老的
}
};
6.3 TreeMap
Map<String, Integer> map = new TreeMap<>();
map.put("C", 3);
map.put("A", 1);
map.put("B", 2);
// 遍历顺序:A → B → C(按 key 自然排序)
| 特性 |
说明 |
| 底层 |
红黑树 |
| 顺序 |
按 key 排序 |
| get/put |
O(log n) |
| null key |
❌ 不允许(因为要排序、比较) |
6.4 Hashtable(⚠ 过时,不推荐)
Map<String, Integer> t = new Hashtable<>(); // ❌ 不推荐
// 全方法 synchronized,性能差
// 不允许 null key/value
// 用 ConcurrentHashMap 替代
6.5 Map 速查
|
HashMap |
LinkedHashMap |
TreeMap |
| 顺序 |
无序 |
插入序 / 访问序 |
key 排序序 |
| get/put |
O(1)~O(log n) |
O(1)~O(log n) |
O(log n) |
| null key |
✅ |
✅ |
❌ |
| 内存 |
小 |
中(多链表指针) |
中(树节点) |
| 用哪个? |
绝大多数场景 |
需要有序遍历 |
需要按 key 排序 |
7. 线程安全集合
前面所有的集合类都不是线程安全的(HashMap、ArrayList 等)。多线程场景需要用以下替代:
| 非线程安全 |
线程安全替代 |
方案 |
HashMap |
ConcurrentHashMap ⭐ |
CAS + synchronized 桶级锁 |
ArrayList |
CopyOnWriteArrayList |
写时复制,读多写少 |
HashSet |
CopyOnWriteArraySet |
写时复制 |
HashSet |
ConcurrentHashMap.newKeySet() |
基于 ConcurrentHashMap |
ArrayDeque |
ConcurrentLinkedDeque |
无锁 CAS |
LinkedList(Queue) |
ConcurrentLinkedQueue |
无锁 CAS |
| 任意 |
Collections.synchronizedXXX() |
全方法 synchronized(性能差) |
选型建议
读多写少 → CopyOnWriteArrayList / CopyOnWriteArraySet
读写均衡 → ConcurrentHashMap / ConcurrentLinkedQueue
简单场景 → Collections.synchronizedList()(不推荐,性能差)
8. 怎么选?决策速查表
┌─── 需要键值对? ───→ Map
│ ├── 无序 → HashMap
│ ├── 按插入序 → LinkedHashMap
│ └── 按 key 排序 → TreeMap
│
需要集合? ──┤
│
└─── 只需要值? ───→ Collection
│
┌─────────────┼─────────────┐
│ │ │
需要重复? 需要去重? 需要 FIFO/LIFO?
│ │ │
List Set Queue/Deque
│ │ │
┌─────┴─────┐ ┌───┴───┐ ┌───┴───┐
读多: 头尾操作多: 无序: 保持序: 排序: 队列: 双端/栈:
ArrayList LinkedList HashSet Linked- TreeSet 优先队列: ArrayDeque
HashSet PriorityQueue
9. 与 JS 的终极对照表
| JS |
Java |
说明 |
[1, 2, 3] |
ArrayList |
动态数组,最常用 |
[] 当队列 .push()+.shift() |
ArrayDeque / LinkedList |
Java 不应该用 List 当队列 |
[] 当栈 .push() + .pop() |
ArrayDeque(用 push/pop) |
替代过时的 Stack |
new Set([1,2,3]) |
HashSet |
去重 |
| --- |
TreeSet |
去重 + 排序(JS 没有内置等价物) |
new Map() |
HashMap |
键值对 |
{}(字符串 key) |
HashMap<String, V> |
最相似的使用方式 |
Map 保持插入序 |
LinkedHashMap |
JS Map 默认保持插入序,Java 需要指定 |
| --- |
TreeMap |
key 排序的 Map(JS 没有) |
| 无(单线程) |
ConcurrentHashMap |
多线程安全 Map |
一句话记住:ArrayList + HashMap 覆盖 80% 场景,HashSet 去重,ArrayDeque 当栈/队列,LinkedHashMap 保序,TreeMap/TreeSet 排序,并发上 ConcurrentHashMap。