Java 集合类全景介绍
面向前端开发者。如果你用 JS 的Array、Set、Map、Object,这篇文章帮你一次性认清 Java 所有集合类。
目录
- 先看 JS:你已会的集合类型
- Java 集合框架全景图
- List:有序可重复
- Set:无序不重复
- Queue / Deque:队列与双端队列
- Map:键值对
- 线程安全集合
- 怎么选?决策速查表
- 与 JS 的终极对照表
1. 先看 JS:你已会的集合类型
// JS 里的集合就这几种constarr=[1,2,3];// ← 什么都能干:列表 + 队列 + 栈constset=newSet([1,2,2]);// ← 去重constmap=newMap();// ← 键值对constobj={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=newArrayList<>();list.add("张三");list.add("李四");list.add("王五");list.get(0);// "张三"list.size();// 3list.remove(1);// 删除"李四"
| 特性 | 说明 |
|---|
| 底层 | Object[]动态数组 |
| 查询 | O(1) — 直接通过下标访问 |
| 插入/删除 | O(n) — 需要搬移后续元素 |
| 扩容 | 默认 10 → 1.5 倍扩容 |
| 适用 | 读多写少(查数据快) |
3.2 LinkedList
List<String>list=newLinkedList<>();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() 或 CopyOnWriteArrayListList<String>vec=newVector<>();// ❌ 不推荐
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=newHashSet<>();set.add("Java");set.add("Python");set.add("Java");// 重复,被忽略set.size();// 2set.contains("Java");// true
| 特性 | 说明 |
|---|
| 底层 | 就是HashMap!(value 固定为PRESENT占位符) |
| 顺序 | 无序 |
| 复杂度 | add/remove/contains 都是 O(1) |
| 去重依据 | hashCode()+equals() |
4.2 LinkedHashSet
Set<String>set=newLinkedHashSet<>();set.add("C");set.add("A");set.add("B");// 遍历顺序:C → A → B(保持插入顺序)
| 特性 | 说明 |
|---|
| 底层 | LinkedHashMap(HashSet + 双向链表维护顺序) |
| 顺序 | 保持插入顺序 |
| 代价 | 比 HashSet 多一点点内存 |
4.3 TreeSet
Set<Integer>set=newTreeSet<>();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=newLinkedList<>();// 三组方法,每组两个:一个抛异常,一个返回特殊值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=newArrayDeque<>();stack.push("A");// 压栈stack.push("B");stack.pop();// "B"(后进先出)// 当队列用Deque<String>queue=newArrayDeque<>();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=newHashMap<>();map.put("张三",95);map.put("李四",87);map.get("张三");// 95map.containsKey("李四");// truemap.remove("张三");// 遍历for(Map.Entry<String,Integer>entry:map.entrySet()){System.out.println(entry.getKey()+" = "+entry.getValue());}// Java 8+ Lambdamap.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=newLinkedHashMap<>();map.put("C",3);map.put("A",1);map.put("B",2);// 遍历顺序:C → A → B(保持插入顺序)
| 特性 | 说明 |
|---|
| 底层 | HashMap + 双向链表 |
| 顺序 | 保持插入顺序(或 accessOrder=true 按访问顺序,实现 LRU) |
// LRU 缓存的经典实现Map<String,Integer>lru=newLinkedHashMap<String,Integer>(16,0.75f,true){@OverrideprotectedbooleanremoveEldestEntry(Map.Entryeldest){returnsize()>100;// 超过 100 条自动删除最老的}};
6.3 TreeMap
Map<String,Integer>map=newTreeMap<>();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=newHashtable<>();// ❌ 不推荐// 全方法 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。