
Java 集合框架是开发中最常用的工具类集合,它统一管理了各类数据存储结构(数组、链表、红黑树等),提供了便捷的增删改查方法,解决了数组固定长度、操作繁琐的痛点。本文从集合框架整体结构出发,详解核心集合类的原理、用法和适用场景,搭配实战代码,让你既能理解底层逻辑,又能在开发中灵活选型。
一、集合框架整体结构:两大核心阵营
Java 集合框架主要分为 Collection(单列集合) 和 Map(双列集合) 两大阵营,所有集合类都围绕这两个核心接口展开:
1. 核心结构概览

2. 核心接口区别
- Collection:存储单个元素的集合,提供统一的元素操作方法(add、remove、iterator 等);
- Map:存储键值对(key-value),key 唯一,value 可重复,提供根据 key 操作 value 的方法(put、get、remove 等)。
二、Collection 接口详解:单列集合的核心
1. List 接口:有序、可重复的'动态数组'
List 接口的核心特点是 有序(元素插入顺序 = 遍历顺序)、可重复,支持通过索引操作元素,适合需要按位置访问、频繁查询的场景。
(1)ArrayList:数组实现的'动态数组'(最常用)
- 底层原理:基于数组实现,默认初始容量为 10,当元素个数超过容量时,会扩容为原来的 1.5 倍(
oldCapacity + (oldCapacity >> 1)),扩容时会复制原数组元素到新数组;
- 核心特点:查询快(数组支持索引随机访问,时间复杂度 O(1))、增删慢(需移动数组元素,时间复杂度 O(n));
- 适用场景:频繁查询、少量增删的场景(如商品列表展示、数据查询结果存储)。
实战代码:ArrayList 常用操作
import java.util.ArrayList;
import java.util.List;
public class ArrayListDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("Java");
System.out.println("添加后:" + list);
String element = list.get(1);
System.out.println("索引 1 的元素:" + element);
list.set(2, "C++");
System.out.println("修改后:" + list);
list.remove(1);
System.out.println("删除后:" + list);
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i) + " ");
}
System.out.println();
for (String s : list) {
System.out.print(s + " ");
}
System.out.println();
java.util.Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String s = iterator.next();
if (s.equals("Java")) {
iterator.remove();
}
}
System.out.println("迭代器删除后:" + list);
}
}
(2)LinkedList:双向链表实现的'链表集合'
- 底层原理:基于双向链表实现,每个元素(节点)包含前驱节点、后继节点的引用,无需连续内存空间;
- 核心特点:查询慢(需遍历链表,时间复杂度 O(n))、增删快(只需修改节点引用,时间复杂度 O(1));
- 适用场景:频繁增删、少量查询的场景(如队列、栈、消息队列)。
实战代码:LinkedList 常用操作
import java.util.LinkedList;
import java.util.List;
public class LinkedListDemo {
public static void main(String[] args) {
List<Integer> list = new LinkedList<>();
list.add(10);
list.add(20);
list.add(30);
System.out.println("添加后:" + list);
list.add(1, 15);
System.out.println("插入后:" + list);
list.remove(Integer.valueOf(20));
System.out.println("删除后:" + list);
LinkedList<Integer> linkedList = (LinkedList<Integer>) list;
linkedList.addFirst(5);
linkedList.addLast(35);
System.out.println("头部 + 尾部添加后:" + linkedList);
int first = linkedList.getFirst();
int last = linkedList.getLast();
System.out.println("头部:" + first + ",尾部:" + last);
}
}
(3)ArrayList vs LinkedList 核心区别
| 特性 | ArrayList | LinkedList |
|---|
| 底层结构 | 数组 | 双向链表 |
| 查询效率 | 高(O(1)) | 低(O(n)) |
| 增删效率 | 低(O(n),需移动元素) | 高(O(1),仅改引用) |
| 内存占用 | 连续内存,可能有冗余 | 非连续内存,每个节点有额外引用开销 |
| 适用场景 | 频繁查询、少量增删 | 频繁增删、少量查询 |
2. Set 接口:无序、不可重复的'集合'
Set 接口的核心特点是 无序(元素插入顺序≠遍历顺序)、不可重复(基于 equals() 和 hashCode() 判断),适合需要去重的场景。
(1)HashSet:哈希表实现的去重集合(最常用)
- 底层原理:基于 HashMap 实现(HashSet 的元素作为 HashMap 的 key,value 为固定常量),利用哈希表保证元素唯一;
- 核心特点:无序、不可重复、查询和增删效率高(时间复杂度 O(1));
- 去重规则:先通过
hashCode() 计算哈希值,若哈希值不同则元素不同;若哈希值相同,再通过 equals() 判断是否相同,两者都相同则视为重复元素。
实战代码:HashSet 常用操作
import java.util.HashSet;
import java.util.Set;
public class HashSetDemo {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("Apple");
set.add("Banana");
set.add("Apple");
System.out.println("添加后:" + set);
set.remove("Banana");
System.out.println("删除后:" + set);
boolean contains = set.contains("Apple");
System.out.println("是否包含 Apple:" + contains);
for (String s : set) {
System.out.print(s + " ");
}
String[] arr = {"Java", "Python", "Java", "C++"};
Set<String> uniqueSet = new HashSet<>();
for (String s : arr) {
uniqueSet.add(s);
}
System.out.println("\n数组去重后:" + uniqueSet);
}
}
(2)LinkedHashSet:有序的去重集合
- 底层原理:基于 HashMap + 双向链表实现,链表记录元素插入顺序,哈希表保证元素唯一;
- 核心特点:有序(插入顺序 = 遍历顺序)、不可重复、效率略低于 HashSet;
- 适用场景:需要去重且保持插入顺序的场景(如用户浏览记录去重)。
(3)TreeSet:排序的去重集合
- 底层原理:基于红黑树实现,元素会按自然顺序(或自定义比较器)排序;
- 核心特点:有序(排序后顺序)、不可重复、查询和增删效率 O(log n);
- 适用场景:需要去重且排序的场景(如成绩排名、数据按关键字排序)。
实战代码:TreeSet 排序示例
import java.util.TreeSet;
public class TreeSetDemo {
public static void main(String[] args) {
TreeSet<Integer> numSet = new TreeSet<>();
numSet.add(30);
numSet.add(10);
numSet.add(20);
System.out.println("自然排序:" + numSet);
TreeSet<String> strSet = new TreeSet<>((s1, s2) -> s2.length() - s1.length());
strSet.add("Apple");
strSet.add("Banana");
strSet.add("Pear");
System.out.println("自定义排序(长度降序):" + strSet);
}
}
3. Queue 接口:先进先出的'队列'
Queue 接口遵循 先进先出(FIFO) 原则,元素从队列尾部添加,从头部删除,适合任务排队、消息传递等场景。
核心方法
offer(E e):添加元素到队列尾部,失败返回 false(推荐使用,不抛出异常);
poll():删除并返回队列头部元素,队列为空返回 null;
peek():返回队列头部元素,不删除,队列为空返回 null;
remove():删除并返回队列头部元素,队列为空抛出异常。
实战代码:LinkedList 实现队列
import java.util.LinkedList;
import java.util.Queue;
public class QueueDemo {
public static void main(String[] args) {
Queue<String> queue = new LinkedList<>();
queue.offer("任务 1");
queue.offer("任务 2");
queue.offer("任务 3");
System.out.println("队列初始化:" + queue);
String head = queue.peek();
System.out.println("队列头部:" + head);
String task = queue.poll();
System.out.println("执行任务:" + task);
System.out.println("执行后队列:" + queue);
}
}
三、Map 接口详解:双列集合的核心
Map 接口存储 键值对(key-value),key 唯一(不可重复),value 可重复,每个 key 对应一个 value,适合通过 key 快速查找 value 的场景(如用户信息存储、配置项管理)。
1. HashMap:哈希表实现的键值对集合(最常用)
- 底层原理:JDK8 之前是'数组 + 链表',JDK8 之后是'数组 + 链表 + 红黑树';当链表长度超过阈值(8)且数组容量≥64 时,链表转为红黑树(提高查询效率);当链表长度≤6 时,红黑树转回链表(节省内存);
- 核心特点:无序、key 唯一、查询和增删效率高(O(1))、线程不安全;
- key 去重规则:同 HashSet,基于
hashCode() 和 equals() 判断。
实战代码:HashMap 常用操作
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class HashMapDemo {
public static void main(String[] args) {
Map<Integer, String> userMap = new HashMap<>();
userMap.put(1001, "张三");
userMap.put(1002, "李四");
userMap.put(1001, "张三三");
System.out.println("添加后:" + userMap);
String username = userMap.get(1001);
System.out.println("用户 1001 的名称:" + username);
boolean hasKey = userMap.containsKey(1002);
System.out.println("是否存在 key=1002:" + hasKey);
userMap.remove(1002);
System.out.println("删除后:" + userMap);
Set<Integer> keySet = userMap.keySet();
for (Integer key : keySet) {
System.out.println( + key + + userMap.get(key));
}
Set<Map.Entry<Integer, String>> entrySet = userMap.entrySet();
(Map.Entry<Integer, String> entry : entrySet) {
System.out.println( + entry.getKey() + + entry.getValue());
}
(String value : userMap.values()) {
System.out.println( + value);
}
}
}
2. LinkedHashMap:有序的键值对集合
- 底层原理:基于 HashMap + 双向链表实现,链表记录键值对的插入顺序或访问顺序;
- 核心特点:有序(插入顺序或访问顺序)、key 唯一、效率略低于 HashMap;
- 适用场景:需要保持键值对顺序的场景(如缓存 LRU 策略、历史操作记录)。
实战代码:LinkedHashMap 有序性
import java.util.LinkedHashMap;
import java.util.Map;
public class LinkedHashMapDemo {
public static void main(String[] args) {
Map<String, Integer> insertOrderMap = new LinkedHashMap<>();
insertOrderMap.put("Apple", 10);
insertOrderMap.put("Banana", 20);
insertOrderMap.put("Pear", 15);
System.out.println("插入顺序:" + insertOrderMap);
Map<String, Integer> accessOrderMap = new LinkedHashMap<>(16, 0.75f, true);
accessOrderMap.put("Apple", 10);
accessOrderMap.put("Banana", 20);
accessOrderMap.put("Pear", 15);
accessOrderMap.get("Banana");
accessOrderMap.get("Apple");
System.out.println("访问顺序:" + accessOrderMap);
}
}
3. TreeMap:排序的键值对集合
- 底层原理:基于红黑树实现,key 按自然顺序或自定义比较器排序;
- 核心特点:有序(key 排序后顺序)、key 唯一、查询和增删效率 O(log n);
- 适用场景:需要按 key 排序的场景(如成绩排名表、字典序查询)。
实战代码:TreeMap 排序
import java.util.TreeMap;
public class TreeMapDemo {
public static void main(String[] args) {
TreeMap<Integer, String> numMap = new TreeMap<>();
numMap.put(3, "C");
numMap.put(1, "A");
numMap.put(2, "B");
System.out.println("自然排序:" + numMap);
TreeMap<String, Integer> strMap = new TreeMap<>((s1, s2) -> s2.length() - s1.length());
strMap.put("Apple", 10);
strMap.put("Banana", 20);
strMap.put("Pear", 15);
System.out.println("自定义排序:" + strMap);
}
}
4. ConcurrentHashMap:线程安全的高效并发集合
- 底层原理:JDK8 之前是'分段锁',JDK8 之后是'CAS+ synchronized',只锁定链表 / 红黑树的节点,不锁定整个数组,并发效率高;
- 核心特点:线程安全、高效并发、key 唯一、无序;
- 适用场景:多线程环境下的键值对存储(如分布式系统中的共享配置、缓存)。
实战代码:ConcurrentHashMap 并发操作
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ConcurrentHashMapDemo {
public static void main(String[] args) throws InterruptedException {
Map<Integer, Integer> map = new ConcurrentHashMap<>();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
map.put(i, i);
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("最终元素个数:" + map.size());
}
}
四、集合框架选型指南(开发必备)
| 场景需求 | 推荐集合类 | 核心原因 |
|---|
| 频繁查询、少量增删 | ArrayList | 数组实现,查询效率 O(1) |
| 频繁增删、少量查询 | LinkedList | 链表实现,增删效率 O(1) |
| 元素去重(无序) | HashSet | 哈希表实现,去重效率高 |
| 元素去重(有序) | LinkedHashSet | 保持插入顺序,兼顾去重和有序 |
| 元素去重 + 排序 | TreeSet | 红黑树排序,自动去重 |
| 任务排队、先进先出 | LinkedList(Queue) | 双端队列实现,增删效率高 |
| 键值对存储(无序、高效) | HashMap | 哈希表实现,查询 O(1) |
| 键值对存储(有序) | LinkedHashMap | 保持插入 / 访问顺序 |
| 键值对存储(排序) | TreeMap | 按 key 排序,支持自定义比较器 |
| 多线程并发键值对存储 | ConcurrentHashMap | 线程安全,并发效率高 |
| 数组去重 | HashSet | 一行代码实现,简洁高效 |
| 用户信息、配置项存储 | HashMap/LinkedHashMap | 按 key 快速查询 value |
五、常见坑点与避坑指南
- ArrayList 遍历中删除元素:使用普通 for 循环删除会导致索引错位,推荐使用迭代器(
Iterator.remove())或增强 for 循环配合标记;
- HashMap 的 key 必须重写 equals() 和 hashCode():自定义对象作为 key 时,需重写这两个方法,否则无法保证去重正确性;
- HashSet/HashMap 无序性:不要依赖遍历顺序,若需有序请使用 LinkedHashSet/LinkedHashMap;
- 线程安全问题:ArrayList、HashMap、HashSet 等都是线程不安全的,多线程环境下需使用 ConcurrentHashMap、CopyOnWriteArrayList 等线程安全集合,或手动加锁;
- TreeSet/TreeMap 的 key 必须可比较:自定义对象作为 key 时,需实现 Comparable 接口或传入 Comparator,否则抛出 ClassCastException。
六、总结
Java 集合框架是开发中的'工具箱',核心是根据业务场景选择合适的存储结构:
- 需按位置访问→List(ArrayList/LinkedList);
- 需去重→Set(HashSet/LinkedHashSet/TreeSet);
- 需排队→Queue(LinkedList);
- 需键值对查询→Map(HashMap/LinkedHashMap/TreeMap);
- 多线程环境→ConcurrentHashMap/CopyOnWriteArrayList。
掌握集合的底层原理(数组、链表、红黑树)能帮助你更精准地选型,而熟练使用常用操作(增删改查、遍历)能提高开发效率。建议多结合实际场景练习,理解不同集合的适用边界,避免'一刀切'使用 ArrayList 或 HashMap。