总体概览:Collection 框架是什么?
Collection 框架是 Java 提供的一组接口、类和算法,位于 java.util 包下,它的主要目的是以统一、高效的方式管理一组对象(也称为元素)。

你可以把它想象成一个“工具箱”,里面有各种不同类型的“容器”(集合),每种容器都有其特定的用途和性能特点,以满足不同的业务场景需求。
核心构成:
- 接口:代表集合的抽象数据类型,是操作集合的“契约”。
List,Set,Queue。 - 实现类:是接口的具体实现,提供了数据存储的具体方式。
ArrayList,LinkedList,HashSet,HashMap。 - 算法:是集合框架中提供的一些静态方法,用于执行有用的操作,如排序、查找等。
Collections.sort()。
核心接口层次结构
理解 Collection 框架的最佳方式是看它的类图结构。
Collection(根接口): 这是最顶层的集合接口,但它本身不直接提供任何具体的实现,它定义了所有集合共有的基本方法,如add(),remove(),size(),iterator()等。List(有序列表):- 特点:元素有序(按插入顺序),且允许重复。
- 常用方法:
get(int index),set(int index, E element),add(int index, E element)。 - 主要实现类:
ArrayList:基于动态数组实现,查询快(O(1)),增删慢(需要移动元素),是List最常用的实现。LinkedList:基于双向链表实现,增删快(只需修改指针),查询慢(需要遍历),额外实现了Deque接口,可以作为队列使用。
Set(无序集):- 特点:元素无序(具体顺序取决于实现),且不允许重复。
- 主要实现类:
HashSet:基于HashMap实现,它不保证元素的顺序,性能很高(O(1)),最常用的Set实现。LinkedHashSet:HashSet的子类,在HashSet的基础上维护了一个双向链表,用于记录元素的插入顺序,它既能保证唯一性,又能保证元素的插入顺序。TreeSet:基于TreeMap(红黑树)实现,元素会按照自然顺序或自定义的比较器进行排序,查询、插入、删除的时间复杂度为 O(log n)。
Queue(队列):- 特点:遵循先进先出 的原则。
- 主要实现类:
LinkedList: 已实现Deque接口,可以作为双端队列使用。PriorityQueue(优先队列): 元素不是按 FIFO 顺序,而是按其自然顺序或自定义的比较器排序,每次取出的都是“优先级”最高的元素。
Map(映射):- 注意:
Map不是Collection的子接口,但它通常被归为集合框架的一部分。 - 特点:存储的是键值对。键 不允许重复,值可以重复,每个键最多映射一个值。
- 主要实现类:
HashMap: 基于哈希表实现,查询、插入、删除的平均时间复杂度为 O(1),不保证键值对的顺序,最常用的Map实现。LinkedHashMap:HashMap的子类,在HashMap的基础上维护了一个双向链表,用于记录键值对的插入顺序或访问顺序。TreeMap: 基于红黑树实现,键会按照自然顺序或自定义的比较器进行排序,时间复杂度为 O(log n)。Hashtable: 一个遗留类,与HashMap类似,但它是线程安全的,不推荐在新代码中使用,因为ConcurrentHashMap是更好的线程安全选择。
- 注意:
如何选择合适的集合?
这是一个非常实际的问题,选择哪个集合,取决于你的业务需求。

| 场景 | 推荐集合 | 理由 |
|---|---|---|
| 需要存储一组对象,且顺序很重要,允许重复 | ArrayList |
数组实现,查询快,是 List 的默认选择。 |
| 需要频繁在中间插入/删除元素 | LinkedList |
链表实现,增删快,但查询慢。 |
| 只需要存储一组不重复的对象,不关心顺序 | HashSet |
哈希实现,性能最高,是 Set 的默认选择。 |
| 需要存储一组不重复的对象,且需要保持插入顺序 | LinkedHashSet |
在 HashSet 基础上维护了插入顺序。 |
| 需要存储一组不重复的对象,且需要按自然/自定义顺序排序 | TreeSet |
红黑树实现,自动排序。 |
| 需要存储键值对,键唯一,不关心顺序 | HashMap |
哈希实现,性能最高,是 Map 的默认选择。 |
| 需要存储键值对,键唯一,且需要保持插入顺序 | LinkedHashMap |
在 HashMap 基础上维护了插入顺序。 |
| 需要存储键值对,键唯一,且需要按键排序 | TreeMap |
红黑树实现,自动按键排序。 |
| 需要先进先出的队列 | LinkedList 或 ArrayDeque |
LinkedList 实现了 Deque,ArrayDeque 是基于数组的双端队列,性能更好。 |
| 需要按优先级出队的队列 | PriorityQueue |
内部自动排序,每次取出优先级最高的元素。 |
常用代码示例
List 示例 (ArrayList)
import java.util.ArrayList;
import java.util.List;
public class ListExample {
public static void main(String[] args) {
// 创建一个 ArrayList
List<String> fruits = new ArrayList<>();
// 添加元素
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Orange");
fruits.add("Apple"); // 允许重复
System.out.println("List: " + fruits); // 输出: [Apple, Banana, Orange, Apple]
// 获取元素
String firstFruit = fruits.get(0);
System.out.println("First fruit: " + firstFruit); // 输出: Apple
// 在指定位置插入元素
fruits.add(1, "Mango");
System.out.println("After adding Mango: " + fruits); // 输出: [Apple, Mango, Banana, Orange, Apple]
// 删除元素
fruits.remove("Orange");
System.out.println("After removing Orange: " + fruits); // 输出: [Apple, Mango, Banana, Apple]
// 遍历 List (三种方式)
System.out.println("--- Traversing List ---");
// 方式1: for-each 循环 (最常用)
for (String fruit : fruits) {
System.out.println(fruit);
}
// 方式2: 使用 Iterator
// fruits.iterator()...
// 方式3: 使用 Java 8 Stream
// fruits.stream().forEach(System.out::println);
}
}
Set 示例 (HashSet)
import java.util.HashSet;
import java.util.Set;
public class SetExample {
public static void main(String[] args) {
// 创建一个 HashSet
Set<String> fruits = new HashSet<>();
// 添加元素
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Orange");
fruits.add("Apple"); // 重复元素不会被添加
System.out.println("Set: " + fruits); // 输出顺序可能与添加顺序不同, [Orange, Apple, Banana]
// 检查元素是否存在
if (fruits.contains("Apple")) {
System.out.println("Apple is in the set.");
}
// 删除元素
fruits.remove("Banana");
System.out.println("After removing Banana: " + fruits); // 输出: [Orange, Apple]
}
}
Map 示例 (HashMap)
import java.util.HashMap;
import java.util.Map;
public class MapExample {
public static void main(String[] args) {
// 创建一个 HashMap
Map<String, Integer> fruitPrices = new HashMap<>();
// 添加键值对
fruitPrices.put("Apple", 10);
fruitPrices.put("Banana", 5);
fruitPrices.put("Orange", 8);
System.out.println("Map: " + fruitPrices); // 输出顺序可能与添加顺序不同
// 获取值
int applePrice = fruitPrices.get("Apple");
System.out.println("Price of Apple: " + applePrice); // 输出: 10
// 检查键是否存在
if (fruitPrices.containsKey("Orange")) {
System.out.println("Orange is in the map.");
}
// 遍历 Map (三种方式)
System.out.println("--- Traversing Map ---");
// 方式1: 遍历键
for (String fruit : fruitPrices.keySet()) {
System.out.println("Fruit: " + fruit);
}
// 方式2: 遍历值
for (Integer price : fruitPrices.values()) {
System.out.println("Price: " + price);
}
// 方式3: 遍历键值对 (最常用)
for (Map.Entry<String, Integer> entry : fruitPrices.entrySet()) {
System.out.println("Fruit: " + entry.getKey() + ", Price: " + entry.getValue());
}
}
}
线程安全与并发
标准的 Collection 实现类(如 ArrayList, HashMap)不是线程安全的,如果在多线程环境下并发修改它们,可能会导致数据不一致或 ConcurrentModificationException。
解决方案:
-
Collections.synchronizedXxx():- 这是一个包装器,可以将非线程安全的集合转换为线程安全的。
List<String> list = Collections.synchronizedList(new ArrayList<>());- 缺点:性能较差,因为它对整个方法进行同步。
-
CopyOnWriteArrayList/CopyOnWriteArraySet:- 适用于读多写少的场景。
- 每次修改操作(add, set等)都会复制整个底层数组,所以写操作很慢,但读操作不加锁,很快。
List<String> list = new CopyOnWriteArrayList<>();
-
ConcurrentHashMap:- 高性能的线程安全
Map实现,它使用分段锁(Java 8后优化为CAS+synchronized)来提高并发性能。 - 是多线程环境下
HashMap的首选替代品。
- 高性能的线程安全
-
ConcurrentLinkedQueue:- 高性能的线程安全
Queue实现。
- 高性能的线程安全
Java 8+ 的新特性
Java 8 为集合框架带来了革命性的变化,主要是引入了 Stream API。
Stream (流):
- 不是数据结构,它是对集合进行操作的管道。
- 特点:链式调用、惰性求值(只有终端操作才会执行)、函数式编程。
示例:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class StreamExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// 1. 过滤出偶数
List<Integer> evenNumbers = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
System.out.println("Even numbers: " + evenNumbers); // 输出: [2, 4, 6, 8, 10]
// 2. 将每个数字平方
List<Integer> squaredNumbers = numbers.stream()
.map(n -> n * n)
.collect(Collectors.toList());
System.out.println("Squared numbers: " + squaredNumbers); // 输出: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
// 3. 计算所有偶数的和
int sumOfEvens = numbers.stream()
.filter(n -> n % 2 == 0)
.mapToInt(Integer::intValue) // 转为 IntStream 以使用 sum()
.sum();
System.out.println("Sum of even numbers: " + sumOfEvens); // 输出: 30
}
}
Stream API 让集合操作变得更加简洁、易读和强大。
| 接口 | 核心特点 | 常用实现类 | 适用场景 |
|---|---|---|---|
List |
有序,可重复 | ArrayList, LinkedList |
需要按顺序存储和访问元素,如任务列表、学生名单。 |
Set |
无序,不重复 | HashSet, LinkedHashSet, TreeSet |
需要存储唯一值,如用户ID、标签、单词列表。 |
Map |
键值对,键唯一 | HashMap, LinkedHashMap, TreeMap |
需要通过键来快速查找值,如字典、缓存、配置信息。 |
Queue |
FIFO | LinkedList, PriorityQueue |
任务调度、消息队列。 |
掌握 Java Collection 框架是成为合格 Java 开发者的必经之路,关键在于理解每种集合的底层原理和适用场景,并在编码中做出正确的选择。
