Java集合框架核心指南
Java集合框架概述
Java集合框架(Java Collections Framework, JCF)是Java标准库中用于存储、操作和聚合数据的一组接口和类。它提供了高效的数据结构和算法,简化了开发过程。
核心接口
Collection接口:所有集合类的根接口,定义了基本操作如添加、删除、遍历等。
List接口概述
List接口是Java集合框架中的核心接口之一,继承自Collection接口,用于表示有序、可重复的元素集合。它允许通过索引(位置)精确控制元素的插入、访问和删除,并提供了丰富的操作方法。
核心特点
- 有序性:元素按插入顺序存储,可通过索引(如
get(int index))访问。 - 可重复性:允许存储相同值的多个元素。
- 动态扩容:底层实现类(如
ArrayList)自动处理容量调整。 - ArrayList:基于动态数组,随机访问高效(O(1)),但插入/删除中间元素较慢(O(n))。
- LinkedList:基于双向链表,插入/删除高效(O(1)),但随机访问较慢(O(n))。
- Vector:线程安全的动态数组,但性能较低,通常被
ArrayList替代。 - 线程安全:
ArrayList和LinkedList非线程安全,多线程环境下需使用Collections.synchronizedList包装或CopyOnWriteArrayList。 - 性能选择:频繁随机访问选
ArrayList,频繁插入/删除选LinkedList。 - 泛型支持:建议使用泛型(如
List<String>)避免类型转换错误。
Set接口概述
Set接口是Java集合框架中的一员,继承自Collection接口,用于存储不重复元素的集合。Set不保证元素的顺序(具体实现类可能提供顺序保证,如LinkedHashSet),主要实现类包括HashSet、TreeSet和LinkedHashSet。
Set接口的核心特性
-
元素唯一性
Set中不允许包含重复元素,添加重复元素时会被自动忽略。判断重复的依据是equals()和hashCode()方法(对于HashSet)或compareTo()方法(对于TreeSet)。 -
无序性(多数实现)
除LinkedHashSet和TreeSet外,HashSet等实现不保证元素的存储顺序与插入顺序一致。 -
允许null元素
大多数实现(如HashSet)允许一个null元素,但TreeSet不允许(会抛出NullPointerException)。
常用实现类对比
| 实现类 | 底层结构 | 是否有序 | 线程安全 | 允许null | 时间复杂度(查询/插入) |
|---|---|---|---|---|---|
HashSet |
哈希表 | 无序 | 否 | 是 | O(1) |
LinkedHashSet |
哈希表+双向链表 | 按插入顺序 | 否 | 是 | O(1) |
TreeSet |
红黑树 | 自然或定制排序 | 否 | 否 | O(log n) |
常用方法示例
Set<String> set = new HashSet<>();
set.add("Apple"); // 添加元素
set.add("Banana");
set.add("Apple"); // 重复元素,添加失败
System.out.println(set.contains("Apple")); // 输出: true
set.remove("Banana"); // 删除元素
适用场景
- 去重操作:快速过滤重复数据。
- 集合运算:使用
addAll()(并集)、retainAll()(交集)等方法。 - 快速查找:
HashSet适合高频查询场景,TreeSet适合需要排序的场景。
注意事项
- 重写
equals()时必须同时重写hashCode(),确保哈希表正常运作。 TreeSet需实现Comparable接口或提供Comparator,否则抛出ClassCastException。- 线程不安全,多线程环境下建议用
Collections.synchronizedSet()包装或使用ConcurrentHashMap实现的Set。
Queue接口概述
Queue是Java集合框架中的接口,继承自Collection接口,用于表示一种先进先出(FIFO)的数据结构。它定义了队列的基本操作,如插入、删除、检查元素等。Queue通常用于任务调度、缓冲处理等场景。
核心方法
插入操作
boolean add(E e): 将元素插入队列,成功返回true,失败时抛出异常(如容量限制)。boolean offer(E e): 尝试插入元素,成功返回true,失败返回false(推荐使用)。
删除操作
E remove(): 移除并返回队列头部元素,队列为空时抛出异常。E poll(): 移除并返回队列头部元素,队列为空时返回null(推荐使用)。
检查操作
E element(): 返回队列头部元素但不移除,队列为空时抛出异常。E peek(): 返回队列头部元素但不移除,队列为空时返回null(推荐使用)。
实现类
-
LinkedList
双向链表实现,支持所有Queue操作,也可作为双端队列使用。Queue<String> queue = new LinkedList<>(); queue.offer("A"); queue.poll(); -
PriorityQueue
基于优先级堆的无界队列,元素按自然顺序或自定义Comparator排序。Queue<Integer> pq = new PriorityQueue<>(); pq.offer(3); pq.poll(); // 可能返回最小元素 -
ArrayDeque
基于循环数组的高效双端队列实现,适合频繁插入/删除操作。
阻塞队列(BlockingQueue)
Queue的子接口,支持线程安全的阻塞操作,常见实现:
LinkedBlockingQueue: 基于链表的可选容量阻塞队列。ArrayBlockingQueue: 固定大小的数组阻塞队列。PriorityBlockingQueue: 带优先级的无界阻塞队列。
使用示例
Queue<Integer> queue = new LinkedList<>();
queue.offer(10);
queue.offer(20);
System.out.println(queue.poll()); // 输出10
System.out.println(queue.peek()); // 输出20
注意事项
- 优先使用
offer、poll、peek等非异常方法。 - 多线程环境需选择线程安全实现(如
ConcurrentLinkedQueue或BlockingQueue)。 PriorityQueue的迭代顺序不保证按优先级排列,仅poll/peek方法体现优先级。
Map接口概述
Map是Java集合框架中的核心接口之一,用于存储键值对(Key-Value)数据。每个键(Key)对应一个值(Value),键不可重复,值可以重复。Map接口提供了丰富的操作方法,适用于需要通过唯一标识快速查找数据的场景。
主要实现类
-
HashMap
- 基于哈希表实现,允许
null键和null值。 - 非线程安全,性能较高。
- 示例代码:
Map<String, Integer> map = new HashMap<>(); map.put("key1", 100); Integer value = map.get("key1"); // 返回100
- 基于哈希表实现,允许
-
LinkedHashMap
- 继承自
HashMap,通过双向链表维护插入顺序或访问顺序。 - 适合需要有序遍历的场景。
- 继承自
-
TreeMap
- 基于红黑树实现,按键的自然顺序或自定义比较器排序。
- 支持范围查询操作(如
subMap())。
-
Hashtable
- 线程安全的遗留类,不允许
null键和null值。 - 通常推荐使用
ConcurrentHashMap替代。
- 线程安全的遗留类,不允许
-
ConcurrentHashMap
- 线程安全且高并发优化的实现,分段锁机制提升性能。
核心方法
-
增删改查
put(K key, V value):添加或更新键值对。remove(Object key):删除指定键的映射。get(Object key):获取键对应的值。containsKey(Object key):检查键是否存在。
-
遍历操作
keySet():返回所有键的集合。values():返回所有值的集合。entrySet():返回所有键值对的集合(Map.Entry对象)。
示例:for (Map.Entry<String, Integer> entry : map.entrySet()) { System.out.println(entry.getKey() + ": " + entry.getValue()); }
-
其他方法
size():返回键值对数量。clear():清空所有映射。putAll(Map<? extends K, ? extends V> m):批量添加映射。
使用注意事项
-
键的唯一性
- 若键为自定义对象,需重写
hashCode()和equals()方法以保证唯一性。
- 若键为自定义对象,需重写
-
性能选择
- 高频读写且无需排序:优先选择
HashMap。 - 需要排序:使用
TreeMap。 - 线程安全场景:选用
ConcurrentHashMap。
- 高频读写且无需排序:优先选择
-
并发问题
- 多线程环境下,非线程安全的
HashMap可能导致数据不一致,需通过Collections.synchronizedMap包装或直接使用ConcurrentHashMap。
- 多线程环境下,非线程安全的
示例场景
-
统计词频
Map<String, Integer> frequency = new HashMap<>(); String[] words = {"apple", "banana", "apple"}; for (String word : words) { frequency.put(word, frequency.getOrDefault(word, 0) + 1); } // 输出:{apple=2, banana=1} -
缓存实现
Map<String, Object> cache = new LinkedHashMap<>(16, 0.75f, true) { @Override protected boolean removeEldestEntry(Map.Entry<String, Object> eldest) { return size() > 100; // 限制缓存大小 } };
并发集合类
Java还提供了线程安全的集合类,位于java.util.concurrent包:
ConcurrentHashMap:线程安全的HashMap。CopyOnWriteArrayList:写时复制的线程安全List。BlockingQueue:支持阻塞操作的队列接口,如ArrayBlockingQueue、LinkedBlockingQueue。
工具类
Collections:提供静态方法用于操作集合(如排序、查找、同步包装等)。Arrays:提供操作数组的工具方法(如转换为集合)。
示例代码片段
// List示例
List<String> arrayList = new ArrayList<>();
arrayList.add("Java");
arrayList.add("Python");
// Set示例
Set<Integer> hashSet = new HashSet<>();
hashSet.add(1);
hashSet.add(2);
// Map示例
Map<String, Integer> hashMap = new HashMap<>();
hashMap.put("Key1", 100);
hashMap.put("Key2", 200);
选择集合类的建议
- 需要快速随机访问:
ArrayList。 - 频繁插入删除:
LinkedList。 - 去重且不关心顺序:
HashSet。 - 需要键值对存储:
HashMap。 - 线程安全场景:
ConcurrentHashMap或CopyOnWriteArrayList。
Java集合框架的设计遵循高内聚低耦合原则,通过统一的接口和泛型支持,极大提升了代码的可复用性和类型安全性。
更多推荐
所有评论(0)