Java 集合框架(Java Collections Framework,简称 JCF)是 Java 提供的一套标准化的数据结构和算法的库,用于存储和操作一组对象。集合框架提供了丰富的接口和实现类,能够满足各种数据存储和操作需求。
1. 集合框架的概述
1.1 什么是集合?
- 集合 是一种容器,用于存储一组数据元素(对象)。
- 与数组不同,集合的大小是可动态扩展的,可以存储不同类型的数据对象。
1.2 集合框架的核心组件
Java 集合框架主要分为以下三大部分:
- 接口(Interfaces):
- 定义了集合的基本行为和操作。
- 如
Collection
、List
、Set
、Map
等。
- 实现类(Implementations):
- 提供了具体的集合实现。
- 如
ArrayList
、HashSet
、HashMap
等。
- 算法(Algorithms):
- 提供了一些通用的操作集合的方法。
- 如排序、搜索、遍历等,通常在
Collections
工具类中实现。
2. 集合框架的层次结构
Java 集合框架是以接口为核心设计的,其层次结构如下:
java.util.Collection (接口)
├── List (接口)
│ ├── ArrayList (实现类)
│ ├── LinkedList (实现类)
│ └── Vector (实现类)
│ └── Stack (实现类)
├── Set (接口)
│ ├── HashSet (实现类)
│ ├── LinkedHashSet (实现类)
│ └── TreeSet (实现类)
└── Queue (接口)
├── PriorityQueue (实现类)
└── LinkedList (实现类)
java.util.Map (接口)
├── HashMap (实现类)
├── LinkedHashMap (实现类)
├── TreeMap (实现类)
└── Hashtable (实现类)
└── Properties (实现类)
3. Collection 接口及其子接口
3.1 Collection 接口
Collection
是所有集合接口的根接口。- 它定义了一些通用操作方法,如添加元素、删除元素、判断集合是否为空等。
常用方法
方法 | 描述 |
---|---|
boolean add(E e) | 添加元素到集合中。 |
boolean remove(Object o) | 从集合中删除指定元素。 |
int size() | 返回集合中元素的数量。 |
boolean isEmpty() | 判断集合是否为空。 |
boolean contains(Object o) | 判断集合是否包含指定元素。 |
Iterator<E> iterator() | 返回集合的迭代器。 |
void clear() | 清空集合中的所有元素。 |
3.2 List 接口
- 特点:有序集合,允许重复元素。
- 实现类:
ArrayList
:基于动态数组,读取效率高,插入和删除效率较低。LinkedList
:基于双向链表,插入和删除效率高。Vector
:线程安全,性能较低,已不推荐使用。
示例:ArrayList
import java.util.ArrayList;
public class ArrayListExample {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
// 添加元素
list.add("Alice");
list.add("Bob");
list.add("Charlie");
// 遍历集合
for (String name : list) {
System.out.println(name);
}
// 删除元素
list.remove("Bob");
System.out.println("删除后: " + list);
}
}
3.3 Set 接口
- 特点:无序集合,不允许重复元素。
- 实现类:
HashSet
:基于哈希表,无序。LinkedHashSet
:基于哈希表和链表,有插入顺序。TreeSet
:基于红黑树,元素有序。
示例:HashSet
import java.util.HashSet;
public class HashSetExample {
public static void main(String[] args) {
HashSet<Integer> set = new HashSet<>();
// 添加元素
set.add(10);
set.add(20);
set.add(10); // 重复元素不会被添加
System.out.println("集合: " + set);
// 检查元素是否存在
System.out.println("包含 20? " + set.contains(20));
}
}
3.4 Queue 接口
- 特点:用于存储需要处理的元素,支持先进先出(FIFO)的操作。
- 实现类:
LinkedList
:既可作为队列,也可作为双端队列。PriorityQueue
:基于优先级的队列,元素按优先级排序。
示例:PriorityQueue
import java.util.PriorityQueue;
public class PriorityQueueExample {
public static void main(String[] args) {
PriorityQueue<Integer> pq = new PriorityQueue<>();
// 添加元素
pq.offer(30);
pq.offer(10);
pq.offer(20);
// 按优先级出队
while (!pq.isEmpty()) {
System.out.println(pq.poll());
}
}
}
4. Map 接口及其实现
Map
是一个键值对(Key-Value)集合,键唯一,值可以重复。
4.1 Map 的实现类
实现类 | 特点 |
---|---|
HashMap | 基于哈希表实现,无序,允许一个 null 键和多个 null 值。 |
LinkedHashMap | 保留插入顺序。 |
TreeMap | 基于红黑树实现,键按自然顺序或自定义比较器排序。 |
Hashtable | 线程安全,但性能较低,不允许键或值为 null 。 |
示例:HashMap
import java.util.HashMap;
public class HashMapExample {
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<>();
// 添加键值对
map.put("Alice", 25);
map.put("Bob", 30);
map.put("Charlie", 35);
// 遍历 Map
for (String key : map.keySet()) {
System.out.println(key + " -> " + map.get(key));
}
// 删除键值对
map.remove("Bob");
System.out.println("删除后: " + map);
}
}
5. Collections 工具类
Collections
是 Java 提供的一个工具类,包含了操作集合的常用方法,如排序、搜索和线程安全包装。
常用方法
方法 | 描述 |
---|---|
Collections.sort(List<T> list) | 对列表进行升序排序。 |
Collections.reverse(List<T> list) | 反转列表中的元素顺序。 |
Collections.shuffle(List<T> list) | 随机打乱列表中的元素顺序。 |
Collections.synchronizedList() | 返回线程安全的 List 。 |
Collections.max(Collection<T>) | 返回集合中的最大值。 |
示例:排序和线程安全
import java.util.ArrayList;
import java.util.Collections;
public class CollectionsExample {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(3);
list.add(1);
list.add(2);
// 排序
Collections.sort(list);
System.out.println("排序后: " + list);
// 随机打乱
Collections.shuffle(list);
System.out.println("打乱后: " + list);
// 获取最大值
System.out.println("最大值: " + Collections.max(list));
}
}
6. 集合框架的特点
6.1 优点
- 统一接口:所有集合类使用相同的操作方法,如
add()
、remove()
。 - 灵活性:支持动态扩展,克服了数组的固定大小限制。
- 多种实现:提供了不同的实现,适合各种场景(如有序、无序、线程安全等)。
- 线程安全支持:提供了线程安全的集合实现,如
Vector
和ConcurrentHashMap
。
6.2 缺点
- 性能开销:相比数组,集合类的性能稍逊,因为它们支持动态扩展和更多功能。
- 类型安全(Java 5 之前):早期版本的集合类不支持泛型,容易发生类型转换问题。
7. 总结
Java 集合框架提供了一整套高效、灵活的数据结构和算法工具,能够满足各种开发需求:
-
核心接口:
Collection
:基础接口。List
、Set
、Queue
:具体子接口。Map
:键值对集合。
-
常见实现:
- 动态数组:
ArrayList
。 - 链表:
LinkedList
。 - 哈希表:
HashMap
。 - 有序集合:
TreeSet
、TreeMap
。
- 动态数组:
-
工具类:
Collections
提供了排序、同步包装等便捷方法。
在实际开发中,根据数据特性和需求选择合适的集合类型,可以显著提高代码的性能和可读性。
Java 集合框架的高级特性与扩展
在前面介绍了 Java 集合框架的基础知识后,我们继续探讨集合框架的一些高级特性、并发集合、常见性能比较,以及如何根据实际场景选择合适的集合类型。
8. 并发集合(Concurrent Collections)
在多线程环境中,普通集合(如 ArrayList
、HashMap
)是线程不安全的,多个线程同时操作可能会导致数据不一致。为了解决这一问题,Java 提供了 并发集合类,它们位于 java.util.concurrent
包中。
8.1 并发集合的优势
- 线程安全:通过内部加锁或无锁机制实现线程安全。
- 高性能:相比早期的线程安全集合(如
Vector
和Hashtable
),并发集合采用了更高效的机制(如分段锁、CAS 操作等)。 - 非阻塞操作:某些并发集合支持无锁算法(如
ConcurrentLinkedQueue
)。
8.2 常用的并发集合
类 | 特点 |
---|---|
ConcurrentHashMap | 高效线程安全的哈希表,支持并发读写,性能高于 Hashtable 。 |
CopyOnWriteArrayList | 线程安全的动态数组,写操作时会复制整个数组,适合读多写少的场景。 |
ConcurrentLinkedQueue | 基于无锁算法的线程安全队列,支持高效的并发操作。 |
LinkedBlockingQueue | 基于链表的阻塞队列,支持生产者-消费者模式。 |
ConcurrentSkipListMap | 基于跳表实现的线程安全有序映射,键值对按自然顺序或自定义比较器排序。 |
ConcurrentSkipListSet | 基于跳表实现的线程安全有序集合。 |
8.3 示例:ConcurrentHashMap
import java.util.concurrent.ConcurrentHashMap;
public class ConcurrentHashMapExample {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// 添加元素
map.put("Alice", 100);
map.put("Bob", 200);
// 多线程操作
Thread t1 = new Thread(() -> map.put("Charlie", 300));
Thread t2 = new Thread(() -> map.put("Dave", 400));
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 遍历集合
map.forEach((key, value) -> System.out.println(key + " -> " + value));
}
}
输出示例:
Alice -> 100
Bob -> 200
Charlie -> 300
Dave -> 400
8.4 示例:CopyOnWriteArrayList
import java.util.concurrent.CopyOnWriteArrayList;
public class CopyOnWriteArrayListExample {
public static void main(String[] args) {
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
// 添加元素
list.add("Alice");
list.add("Bob");
// 遍历期间修改
for (String name : list) {
System.out.println(name);
list.add("Charlie"); // 不会影响当前遍历
}
System.out.println("最终列表: " + list);
}
}
输出:
Alice
Bob
最终列表: [Alice, Bob, Charlie]
9. 集合框架的性能比较
在选择集合类时,需要根据具体场景(如数据量、操作类型、多线程等)来决定。以下是常见集合的性能对比和适用场景:
9.1 List 的性能比较
实现类 | 随机访问 | 插入/删除(中间位置) | 线程安全 | 适用场景 |
---|---|---|---|---|
ArrayList | 快(O(1)) | 慢(O(n)) | 否 | 适合频繁读取的场景。 |
LinkedList | 慢(O(n)) | 快(O(1)) | 否 | 适合频繁插入和删除的场景。 |
CopyOnWriteArrayList | 慢(O(n)) | 慢(O(n)) | 是 | 适合多线程读多写少的场景。 |
9.2 Set 的性能比较
实现类 | 查找速度 | 插入/删除 | 有序性 | 线程安全 | 适用场景 |
---|---|---|---|---|---|
HashSet | 快(O(1)) | 快(O(1)) | 无序 | 否 | 适合快速查找唯一元素的场景。 |
LinkedHashSet | 快(O(1)) | 快(O(1)) | 按插入顺序排序 | 否 | 需要插入顺序时使用。 |
TreeSet | 慢(O(log n)) | 慢(O(log n)) | 按自然顺序排序 | 否 | 需要排序的场景。 |
ConcurrentSkipListSet | 慢(O(log n)) | 慢(O(log n)) | 按自然顺序排序 | 是 | 多线程环境下的有序集合。 |
9.3 Map 的性能比较
实现类 | 查找速度 | 插入/删除 | 有序性 | 线程安全 | 适用场景 |
---|---|---|---|---|---|
HashMap | 快(O(1)) | 快(O(1)) | 无序 | 否 | 适合快速查找键值对的场景。 |
LinkedHashMap | 快(O(1)) | 快(O(1)) | 按插入顺序排序 | 否 | 需要按插入顺序遍历键值对时使用。 |
TreeMap | 慢(O(log n)) | 慢(O(log n)) | 按自然顺序排序 | 否 | 需要键自动排序时使用。 |
ConcurrentHashMap | 快(O(1)) | 快(O(1)) | 无序 | 是 | 多线程环境下的高效键值对存储。 |
ConcurrentSkipListMap | 慢(O(log n)) | 慢(O(log n)) | 按自然顺序排序 | 是 | 多线程环境下需要排序的键值对存储。 |
10. 集合框架的扩展与高级技巧
10.1 使用泛型
Java 集合框架支持泛型,可以在编译时检查类型,从而避免运行时的类型转换异常。
示例:使用泛型
import java.util.ArrayList;
import java.util.List;
public class GenericsExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Alice");
list.add("Bob");
// 遍历集合,无需类型转换
for (String name : list) {
System.out.println(name);
}
}
}
10.2 自定义排序
使用 Comparator
或 Comparable
接口可以对集合中的元素进行自定义排序。
示例:Comparator 自定义排序
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class CustomSortExample {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Charlie");
list.add("Alice");
list.add("Bob");
// 按字符串长度排序
Collections.sort(list, Comparator.comparingInt(String::length));
System.out.println(list); // 输出: [Bob, Alice, Charlie]
}
}
10.3 集合的不可变性
Java 提供了 Collections.unmodifiableList()
等方法,创建只读集合,防止修改。
示例:不可变集合
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
public class UnmodifiableListExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Alice");
list.add("Bob");
// 创建不可变集合
List<String> unmodifiableList = Collections.unmodifiableList(list);
// 尝试修改将抛出异常
// unmodifiableList.add("Charlie"); // UnsupportedOperationException
}
}
10.4 使用 Streams 操作集合
Java 8 引入了 Stream API,可以对集合进行高效的数据处理。
示例:Stream 操作集合
import java.util.ArrayList;
import java.util.List;
public class StreamExample {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
// 使用 Stream 过滤和映射
numbers.stream()
.filter(n -> n > 1) // 过滤大于 1 的元素
.map(n -> n * 2) // 每个元素乘以 2
.forEach(System.out::println); // 输出结果
}
}
输出:
4
6
11. 总结与实践建议
11.1 集合框架的核心点
- 灵活性:支持多种数据结构(如列表、集合、队列、映射)。
- 线程安全支持:提供线程安全的集合(如
ConcurrentHashMap
)。 - 泛型支持:提高代码的类型安全性。
- 工具类支持:
Collections
和Streams
提供了丰富的操作方法。
11.2 实践建议
- 选择合适的集合:
- 频繁读取:
ArrayList
。 - 频繁插入/删除:
LinkedList
。 - 无序唯一:
HashSet
。 - 有序唯一:
TreeSet
。
- 频繁读取:
- 多线程环境:
- 使用并发集合(如
ConcurrentHashMap
)。
- 使用并发集合(如
- 性能优化:
- 如果集合大小已知,初始化时指定容量,减少扩容开销。
- 简化操作:
- 使用 Stream API 处理集合数据,代码更简洁。
熟练掌握 Java 集合框架,结合实际场景选择合适的实现,可以帮助开发者编写高效、健壮的代码。