Java 集合框架(Collection Framework)是 Java 语言中处理对象集合的核心 API,位于
java.util 包下。它提供了统一的接口规范和丰富的实现类,用于存储、操作和管理一组对象,解决了数组长度固定、类型单一等局限性。本文将从框架架构、核心接口、实现类特性到实战场景,全面解析 Java 集合框架,帮助你理解其设计思想与最佳实践。
Java 集合框架的核心是接口(定义规范)和实现类(提供具体功能),按数据结构可分为两大体系:Collection(单值集合) 和Map(键值对集合)。整体层次结构如下:
java.util
├─ Collection(单值集合根接口)
│ ├─ List(有序、可重复)
│ │ ├─ ArrayList(动态数组)
│ │ ├─ LinkedList(双向链表)
│ │ └─ Vector(线程安全动态数组,已过时)
│ │ └─ Stack(栈,继承自Vector,已过时)
│ ├─ Set(无序、不可重复)
│ │ ├─ HashSet(哈希表实现)
│ │ ├─ TreeSet(红黑树实现,有序)
│ │ └─ LinkedHashSet(哈希表+链表,维持插入顺序)
│ └─ Queue(队列,FIFO)
│ ├─ LinkedList(双向链表实现的队列)
│ ├─ PriorityQueue(优先级队列,基于堆)
│ └─ Deque(双端队列)
│ └─ ArrayDeque(数组实现的双端队列)
└─ Map(键值对集合根接口)├─ HashMap(哈希表实现)├─ TreeMap(红黑树实现,键有序)├─ LinkedHashMap(哈希表+链表,维持插入/访问顺序)└─ Hashtable(线程安全哈希表,已过时)└─ Properties(键值均为字符串的配置类)
- 接口标准化:通过
Collection、List、Set、Map 等接口定义统一操作(如 add()、remove()、iterator()),实现类遵循接口规范,便于替换和扩展。
- 数据结构封装:将数组、链表、红黑树、哈希表等数据结构封装为实现类,开发者无需关注底层细节,直接调用 API 即可。
- 泛型支持:JDK 5+ 引入泛型(如
List<String>),解决集合元素类型不安全问题,避免运行时类型转换错误。
Collection 是所有单值集合的根接口,定义了操作集合的通用方法,主要包括:
注意:Collection 接口未提供索引访问方法(如 get(int index)),这类方法由子接口 List 定义。
List 接口继承自 Collection,特点是元素有序(插入顺序)、可重复,支持通过索引访问元素,是最常用的集合类型之一。
- 核心是动态扩容数组:初始容量为 10,当元素数量超过当前容量时,自动扩容为原容量的 1.5 倍(
oldCapacity + (oldCapacity >> 1))。
- 存储结构:连续内存空间,元素按索引顺序存储,类似数组但长度可动态调整。
- 时间复杂度:
- 随机访问(
get(int index)):O(1)(直接通过索引定位);
- 尾部插入 / 删除(
add(E e)、remove(int size-1)):O(1);
- 中间插入 / 删除(
add(int index, E e)):O(n)(需移动后续元素)。
- 优缺点:
- 优点:查询效率高,适合读多写少场景;
- 缺点:中间插入 / 删除效率低,扩容时可能浪费内存(需复制旧数组到新数组)。
import java.util.ArrayList;
import java.util.List;public class ArrayListDemo {public static void main(String[] args) {List<String> fruits = new ArrayList<>();
- 核心是双向链表:每个节点(
Node)包含 prev(前驱节点引用)、item(元素值)、next(后继节点引用)。
- 存储结构:非连续内存空间,元素通过节点引用关联,无需预先分配固定大小的内存。
- 时间复杂度:
- 随机访问(
get(int index)):O(n)(需从头 / 尾遍历到指定索引);
- 头部 / 尾部插入 / 删除(
addFirst(E e)、removeLast()):O(1);
- 中间插入 / 删除(已知节点位置时):
O(1)(仅需修改节点引用),但定位节点仍需 O(n)。
- 优缺点:
- 优点:头尾操作效率高,内存利用率灵活(无需连续空间);
- 缺点:查询效率低,不适合频繁随机访问。
import java.util.LinkedList;
import java.util.List;public class LinkedListDemo {public static void main(String[] args) {List<Integer> numbers = new LinkedList<>();
Set 接口继承自 Collection,特点是元素无序(插入顺序不保证)、不可重复,适合存储唯一值(如用户 ID、标签)。其核心是去重机制:通过元素的 hashCode() 和 equals() 方法判断是否重复(先比较哈希值,哈希值相同再比较内容)。
- 本质是HashMap 的封装:
HashSet 内部维护一个 HashMap,元素作为 HashMap 的 key 存储(value 为固定的空对象 PRESENT)。
- 去重逻辑:同
HashMap 的 key 去重,依赖元素重写 hashCode() 和 equals() 方法。
- 时间复杂度:添加 / 删除 / 查询均为
O(1)(哈希表理想情况,无哈希冲突);
- 无序性:元素存储位置由哈希值决定,遍历顺序与插入顺序无关;
- 允许 null 元素:但仅能有一个
null(因不可重复)。
import java.util.HashSet;
import java.util.Set;public class HashSetDemo {public static void main(String[] args) {Set<String> cities = new HashSet<>();
- 本质是TreeMap 的封装:内部维护一个
TreeMap,元素作为 TreeMap 的 key 存储,依赖红黑树(自平衡二叉查找树)实现排序。
- 排序逻辑:
- 自然排序:元素实现
Comparable 接口,重写 compareTo() 方法;
- 定制排序:创建
TreeSet 时传入 Comparator 比较器。
- 时间复杂度:添加 / 删除 / 查询均为
O(log n)(红黑树高度为 log n);
- 有序性:元素按排序规则升序排列(默认自然排序);
- 不允许 null 元素:插入
null 会抛 NullPointerException。
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;public class TreeSetDemo {public static void main(String[] args) {
- 继承自
HashSet,内部使用LinkedHashMap(哈希表 + 双向链表),通过链表记录元素插入顺序。
- 兼具
HashSet 的查询效率(O(1))和 LinkedList 的顺序性(插入顺序);
- 内存开销略高于
HashSet(需维护链表)。
需去重且关注插入顺序的场景(如日志记录、历史操作记录)。
Queue 接口继承自 Collection,定义了FIFO(先进先出) 的队列操作规范,主要用于实现队列、缓冲区等场景。
LinkedList 实现了 Queue 接口,可作为队列使用,核心方法:
import java.util.LinkedList;
import java.util.Queue;public class QueueDemo {public static void main(String[] args) {Queue<String> queue = new LinkedList<>();
- 基于小顶堆(默认)实现,元素按优先级出队(优先级最高的元素先出队)。
- 排序逻辑:同
TreeSet,支持自然排序或定制排序。
- 出队顺序由优先级决定,而非插入顺序;
- 时间复杂度:入队 / 出队
O(log n),查看队头 O(1)。
import java.util.PriorityQueue;
import java.util.Queue;public class PriorityQueueDemo {public static void main(String[] args) {
Map 接口是独立于 Collection 的另一大体系,用于存储键值对(key-value),其中 key 唯一(不可重复),value 可重复。key 的去重逻辑同 Set(依赖 hashCode() 和 equals())。
- 数组 + 链表 + 红黑树:
- 数组(桶):每个索引对应一个链表或红黑树;
- 链表:当哈希冲突时,元素以链表形式存储;
- 红黑树:当链表长度超过 8 且数组容量 ≥ 64 时,链表转为红黑树(优化查询效率)。
- 扩容机制:初始容量 16,负载因子 0.75(当元素数 > 容量 × 负载因子时,扩容为原容量的 2 倍)。
- 时间复杂度:理想情况
O(1)(哈希表无冲突),红黑树场景 O(log n);
- 无序性:
key 的存储顺序与插入顺序无关;
- 允许 null:
key 最多一个 null,value 可多个 null;
- 线程不安全:多线程并发修改可能导致死循环(JDK 1.7)或数据异常。
import java.util.HashMap;
import java.util.Map;public class HashMapDemo {public static void main(String[] args) {Map<String, Integer> scores = new HashMap<>();
- 基于红黑树,
key 按排序规则(自然排序或定制排序)存储,遍历顺序为升序。
- 时间复杂度:添加 / 删除 / 查询均为
O(log n);
- 有序性:
key 按排序规则排列,支持范围查询(如 subMap()、headMap());
- 不允许 null key:
key 为 null 会抛 NullPointerException。
import java.util.Map;
import java.util.TreeMap;public class TreeMapDemo {public static void main(String[] args) {
- 继承自
HashMap,内部通过双向链表记录 key 的顺序,支持两种顺序:
- 插入顺序(默认):遍历顺序与插入顺序一致;
- 访问顺序(
accessOrder=true):每次访问(get())元素后,该元素移至链表尾部,适合实现 LRU 缓存。
import java.util.LinkedHashMap;
import java.util.Map;public class LinkedHashMapDemo {public static void main(String[] args) {
提供静态方法操作集合,如排序、查找、同步包装等:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;public class CollectionsDemo {public static void main(String[] args) {List<Integer> list = new ArrayList<>();list.add(3);list.add(1);list.add(2);
提供数组与集合的转换方法(如 asList()):
import java.util.Arrays;
import java.util.List;public class ArraysDemo {public static void main(String[] args) {
Java 集合框架中,ArrayList、HashMap、HashSet 等均为线程不安全(多线程并发修改可能导致数据异常),线程安全的集合解决方案:
-
使用同步包装类:Collections.synchronizedList()、synchronizedMap() 等,通过加锁实现线程安全,但性能低(全局锁)。
-
使用 JUC 并发集合:java.util.concurrent 包下的集合(如 CopyOnWriteArrayList、ConcurrentHashMap),采用更高效的并发策略(如读写分离、分段锁),适合高并发场景。
-
手动同步:在多线程操作时,通过 synchronized 或 Lock 手动加锁,灵活但需注意锁粒度。
Java 集合框架的核心是 “根据场景选结构”,选择时需关注:
- 操作类型:查询多→
ArrayList/HashMap;增删多(头尾)→LinkedList;需排序→TreeSet/TreeMap。
- 顺序需求:需插入顺序→
LinkedList/LinkedHashSet/LinkedHashMap;需排序→Tree 系列。
- 线程安全:单线程→普通集合;多线程→JUC 并发集合(如
ConcurrentHashMap)。
- 性能考量:哈希表(
Hash 系列)平均 O(1) 效率最高;红黑树(Tree 系列)O(log n) 适合排序场景。