Java集合类
Java 集合类是编程中最常用的数据结构,它们被封装在 java.util 包下,核心目的是存储、管理和操作一组对象。我会从分类、底层原理、使用场景三个维度,用通俗易懂的方式帮你梳理清楚。
一、Java 集合的整体分类
Java 集合主要分为两大体系,再细分不同实现类:
graph TD
A[Java集合] --> B[Collection接口]
A --> C[Map接口]
B --> B1[List:有序、可重复]
B --> B2[Set:无序、不可重复]
B --> B3[Queue:队列,先进先出]
B1 --> B11[ArrayList]
B1 --> B12[LinkedList]
B1 --> B13[Vector]
B2 --> B21[HashSet]
B2 --> B22[TreeSet]
B2 --> B23[LinkedHashSet]
B3 --> B31[LinkedList]
B3 --> B32[PriorityQueue]
C --> C1[HashMap]
C --> C2[TreeMap]
C --> C3[LinkedHashMap]
C --> C4[Hashtable]
二、核心集合类的底层原理 & 使用场景
1. List 系列(有序、可重复)
| 集合类 | 底层原理 | 核心特点 | 使用场景 |
|---|---|---|---|
| ArrayList | 基于动态数组实现(初始容量10,扩容时按1.5倍扩容) | 查询快、增删慢(需移动元素) | 读多写少的场景,如:展示列表数据、缓存少量固定数据、遍历查询操作多的场景 |
| LinkedList | 基于双向链表实现(每个节点包含前驱、后继指针) | 查询慢、增删快(无需移动元素) | 写多读少的场景,如:频繁插入/删除元素、实现队列/栈、消息队列缓冲区 |
| Vector | 基于动态数组实现(线程安全,方法加了synchronized) |
线程安全、性能低 | 几乎不用(被CopyOnWriteArrayList替代),仅兼容老代码 |
代码示例(ArrayList vs LinkedList):
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class ListDemo {
public static void main(String[] args) {
// ArrayList:适合查询
List<String> arrayList = new ArrayList<>();
arrayList.add("Java");
arrayList.add("Python");
System.out.println("ArrayList查询:" + arrayList.get(0)); // 直接通过索引获取,O(1)
// LinkedList:适合增删
List<String> linkedList = new LinkedList<>();
linkedList.addFirst("前端"); // 头部插入,O(1)
linkedList.addLast("后端"); // 尾部插入,O(1)
linkedList.remove(0); // 头部删除,O(1)
}
}
2. Set 系列(无序、不可重复)
| 集合类 | 底层原理 | 核心特点 | 使用场景 |
|---|---|---|---|
| HashSet | 基于HashMap实现(值存在HashMap的key中,value固定为一个空对象) | 无序、查询快、不可重复 | 去重场景,如:存储用户ID、过滤重复数据 |
| LinkedHashSet | 基于LinkedHashMap实现(保留插入顺序) | 有序(插入顺序)、不可重复 | 既需要去重,又需要保留插入顺序的场景,如:记录用户操作日志(去重+有序) |
| TreeSet | 基于TreeMap实现(底层是红黑树) | 可排序(自然排序/自定义排序) | 需排序的去重场景,如:按价格排序商品ID、按分数排序学生学号 |
代码示例(HashSet vs TreeSet):
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
public class SetDemo {
public static void main(String[] args) {
// HashSet:去重,无序
Set<Integer> hashSet = new HashSet<>();
hashSet.add(3);
hashSet.add(1);
hashSet.add(3); // 重复元素,不会存储
System.out.println("HashSet:" + hashSet); // 输出:[1, 3](无序)
// TreeSet:去重+排序
Set<Integer> treeSet = new TreeSet<>();
treeSet.add(3);
treeSet.add(1);
treeSet.add(2);
System.out.println("TreeSet:" + treeSet); // 输出:[1, 2, 3](有序)
}
}
3. Map 系列(键值对、键唯一)
| 集合类 | 底层原理 | 核心特点 | 使用场景 |
|---|---|---|---|
| HashMap | JDK1.8前:数组+链表;JDK1.8后:数组+链表+红黑树(链表长度≥8转红黑树) | 无序、查询快、非线程安全 | 最常用的键值对存储,如:缓存用户信息(key=用户ID,value=用户对象)、配置参数 |
| LinkedHashMap | 基于HashMap+双向链表(保留插入顺序/访问顺序) | 有序(插入/访问顺序)、非线程安全 | 需保留键值对顺序的场景,如:实现LRU缓存(按访问顺序淘汰)、记录接口调用顺序 |
| TreeMap | 基于红黑树实现 | 可排序(按key排序)、非线程安全 | 需按key排序的键值对场景,如:按时间戳排序日志、按金额排序订单 |
| Hashtable | 基于数组+链表实现(方法加synchronized,线程安全) |
线程安全、性能低、不允许null键/值 | 几乎不用(被ConcurrentHashMap替代),仅兼容老代码 |
代码示例(HashMap vs TreeMap):
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
public class MapDemo {
public static void main(String[] args) {
// HashMap:无序键值对
Map<String, Integer> hashMap = new HashMap<>();
hashMap.put("B", 2);
hashMap.put("A", 1);
System.out.println("HashMap:" + hashMap); // 输出:{A=1, B=2}(无序,JDK1.8后可能有序,本质是哈希顺序)
// TreeMap:按key排序
Map<String, Integer> treeMap = new TreeMap<>();
treeMap.put("B", 2);
treeMap.put("A", 1);
System.out.println("TreeMap:" + treeMap); // 输出:{A=1, B=2}(按key自然排序)
}
}
4. Queue 系列(队列,先进先出)
| 集合类 | 底层原理 | 核心特点 | 使用场景 |
|---|---|---|---|
| LinkedList | 双向链表 | 非阻塞、双端队列 | 普通队列/栈实现,如:任务临时存储 |
| PriorityQueue | 基于二叉堆实现 | 优先级队列 | 按优先级处理任务,如:任务调度器、医院挂号系统 |
三、线程安全的集合补充
日常开发中,多线程场景需要线程安全的集合,常用的有:
ConcurrentHashMap:替代Hashtable,分段锁(JDK1.8改为CAS+同步锁),性能更高;CopyOnWriteArrayList:替代Vector,写时复制,适合读多写少;CopyOnWriteArraySet:基于CopyOnWriteArrayList,线程安全的Set。
总结
- 选List:需要有序、可重复,读多写少用ArrayList,写多读少用LinkedList;
- 选Set:需要去重,无序用HashSet,有序用LinkedHashSet,排序用TreeSet;
- 选Map:需要键值对,无序用HashMap,有序用LinkedHashMap,排序用TreeMap,多线程用ConcurrentHashMap。
核心记忆点:查询快选数组实现(ArrayList/HashMap),增删快选链表实现(LinkedList),排序选红黑树实现(TreeSet/TreeMap)。
百流积聚,江河是也;文若化风,可以砾石。

浙公网安备 33010602011771号