Java 集合框架 (Collections Framework) 是 Java 平台提供的一组接口、实现类和算法,用于存储、操作和管理对象集合。 它是 Java 编程中最核心、最常用的 API 之一。
一、 集合框架概述 (Overview)
-
定义:
- 集合框架是一个统一的架构,用于表示和操作集合,允许它们独立于表示的细节进行操作。
- 集合框架提供了一组通用的接口和类,用于存储不同类型的对象,并提供了对这些对象进行添加、删除、查找、遍历、排序等操作。
-
优点:
- 减少编程工作量: 提供了现成的、高效的数据结构和算法,无需从头开始编写。
- 提高程序性能: 集合框架中的实现类经过了优化,具有良好的性能。
- 提高代码可读性和可维护性: 使用统一的接口和类,使代码更易于理解和维护。
- 促进代码复用: 集合框架中的接口和类可以在不同的程序中重复使用。
- 提供互操作性: 基于接口的集合框架允许不同类型的集合之间进行互操作。
-
组成部分:
- 接口 (Interfaces): 定义了集合的通用行为,例如
Collection
,List
,Set
,Map
,Queue
,Deque
等。 - 实现类 (Implementations): 提供了接口的具体实现,例如
ArrayList
,LinkedList
,HashSet
,TreeSet
,HashMap
,TreeMap
等。 - 算法 (Algorithms): 提供了一些常用的算法,例如排序、查找、打乱顺序等,这些算法可以用于操作各种类型的集合。
- 接口 (Interfaces): 定义了集合的通用行为,例如
二、 核心接口 (Core Interfaces)
Java 集合框架的核心接口主要分为两大类:
-
Collection
接口:Collection
接口是所有集合接口的根接口,它定义了集合的基本操作,例如添加元素、删除元素、判断是否包含元素、获取集合大小、遍历集合等。Collection
接口的主要子接口:List
接口: 有序集合,允许重复元素。Set
接口: 无序集合,不允许重复元素。Queue
接口: 队列,通常用于存储等待处理的元素(FIFO - 先进先出)。Deque
接口: 双端队列,可以在两端添加和删除元素。
-
Map
接口:Map
接口用于存储键值对 (key-value pairs),每个键映射到一个值。Map
接口中的键不能重复,值可以重复。Map
接口的主要实现类:HashMap
TreeMap
LinkedHashMap
接口层次结构 (简化版):
Collection<E>
/ | \
/ | \
/ | \
/ | \
List<E> Set<E> Queue<E>
/ \ | / \
/ \ | / \
ArrayList LinkedList HashSet Deque<E>
| |
TreeSet ArrayDeque
PriorityQueue
Map<K, V>
/ | \
/ | \
HashMap TreeMap LinkedHashMap
三、 常用接口和实现类详解
-
Collection<E>
接口:- 常用方法:
add(E e)
: 添加元素。addAll(Collection<? extends E> c)
: 添加另一个集合中的所有元素。remove(Object o)
: 删除元素。removeAll(Collection<?> c)
: 删除另一个集合中包含的所有元素。retainAll(Collection<?> c)
: 仅保留此集合中包含在另一个集合中的元素(交集)。clear()
: 删除所有元素。contains(Object o)
: 判断是否包含指定元素。containsAll(Collection<?> c)
: 判断是否包含另一个集合中的所有元素。isEmpty()
: 判断集合是否为空。size()
: 返回集合中元素的数量。iterator()
: 返回一个用于遍历集合的迭代器。toArray()
: 将集合转换为数组。toArray(T[] a)
: 将集合转换为指定类型的数组。
- 常用方法:
-
List<E>
接口:-
特点: 有序集合,允许重复元素。 可以通过索引访问元素。
-
常用方法 (除了
Collection
接口的方法外):get(int index)
: 获取指定索引处的元素。set(int index, E element)
: 替换指定索引处的元素。add(int index, E element)
: 在指定索引处插入元素。remove(int index)
: 删除指定索引处的元素。indexOf(Object o)
: 返回指定元素第一次出现的索引。lastIndexOf(Object o)
: 返回指定元素最后一次出现的索引。subList(int fromIndex, int toIndex)
: 返回指定范围的子列表。listIterator()
: 返回一个列表迭代器,可以双向遍历列表,并修改列表。
-
常用实现类:
ArrayList
: 基于动态数组实现,查询快,插入/删除慢 (尤其是在中间插入/删除)。 非线程安全。LinkedList
: 基于双向链表实现,插入/删除快 (尤其是在中间插入/删除),查询慢。 非线程安全。Vector
: 类似于ArrayList
,但线程安全 (方法都使用synchronized
修饰)。 性能较低。Stack
: 继承自Vector
,表示栈。
-
-
Set<E>
接口:- 特点: 无序集合,不允许重复元素。
- 常用方法 (与
Collection
接口基本相同): - 常用实现类:
HashSet
: 基于哈希表实现,无序,查找、添加、删除速度快。 非线程安全。LinkedHashSet
: 基于哈希表和链表实现,按照插入顺序排序。 非线程安全。TreeSet
: 基于红黑树实现,有序 (可以按照自然顺序或自定义比较器排序)。 非线程安全。
-
Queue<E>
接口:-
特点: 队列,通常用于存储等待处理的元素,遵循 FIFO (先进先出) 原则。
-
常用方法:
add(E e)
/offer(E e)
: 添加元素到队尾 (前者在队列满时抛出异常,后者返回false
)。remove()
/poll()
: 移除并返回队头元素 (前者在队列为空时抛出异常,后者返回null
)。element()
/peek()
: 返回队头元素,但不移除 (前者在队列为空时抛出异常,后者返回null
)。
-
常用实现类:
LinkedList
: 也实现了Queue
接口,可以用作队列。PriorityQueue
: 优先级队列,元素按照优先级排序。ArrayBlockingQueue
: 基于数组的有界阻塞队列。LinkedBlockingQueue
: 基于链表的可选有界阻塞队列。PriorityBlockingQueue
: 无界阻塞优先级队列。DelayQueue
: 延迟队列,元素只有在延迟时间到期后才能被取出。SynchronousQueue
: 同步队列,每个插入操作必须等待另一个线程的移除操作,反之亦然。
-
-
Deque<E>
接口:-
特点: 双端队列 (Double Ended Queue),可以在两端添加和删除元素。
-
常用方法:
addFirst(E e)
,offerFirst(E e)
addLast(E e)
,offerLast(E e)
removeFirst()
,pollFirst()
removeLast()
,pollLast()
getFirst()
,peekFirst()
getLast()
,peekLast()
-
常用实现类:
LinkedList
: 也实现了Deque
接口。ArrayDeque
: 基于数组实现的双端队列。
-
-
Map<K, V>
接口:-
特点: 存储键值对 (key-value pairs),键不能重复,值可以重复。
-
常用方法:
put(K key, V value)
: 添加键值对。get(Object key)
: 根据键获取值。remove(Object key)
: 根据键删除键值对。containsKey(Object key)
: 判断是否包含指定的键。containsValue(Object value)
: 判断是否包含指定的值。isEmpty()
: 判断 Map 是否为空。size()
: 返回 Map 中键值对的数量。keySet()
: 返回所有键的Set
集合。values()
: 返回所有值的Collection
集合。entrySet()
: 返回所有键值对的Set
集合 (每个元素是一个Map.Entry
对象)。
-
常用实现类:
HashMap
: 基于哈希表实现,无序,查找、添加、删除速度快。 非线程安全。 允许null
键和null
值。TreeMap
: 基于红黑树实现,有序 (可以按照自然顺序或自定义比较器排序)。 非线程安全。LinkedHashMap
: 基于哈希表和链表实现,按照插入顺序或访问顺序排序。 非线程安全。Hashtable
: 类似于HashMap
,但线程安全 (方法都使用synchronized
修饰)。 性能较低。 不允许null
键和null
值。ConcurrentHashMap
: 线程安全的HashMap
,使用分段锁 (Segment Locking) 或 CAS 操作实现高效的并发访问。
-
四、常用算法 (Collections Class)
java.util.Collections
类提供了一组静态方法,用于操作集合:
- 排序:
sort(List<T> list)
,sort(List<T> list, Comparator<? super T> c)
- 查找:
binarySearch(List<? extends Comparable<? super T>> list, T key)
,binarySearch(List<? extends T> list, T key, Comparator<? super T> c)
- 最大/最小值:
max(Collection<? extends T> coll)
,min(Collection<? extends T> coll)
,max(Collection<? extends T> coll, Comparator<? super T> comp)
,min(Collection<? extends T> coll, Comparator<? super T> comp)
- 反转:
reverse(List<?> list)
- 打乱顺序:
shuffle(List<?> list)
- 填充:
fill(List<? super T> list, T obj)
- 复制:
copy(List<? super T> dest, List<? extends T> src)
- 同步:
synchronizedCollection(Collection<T> c)
,synchronizedList(List<T> list)
,synchronizedSet(Set<T> s)
,synchronizedMap(Map<K,V> m)
(用于创建线程安全的集合) - 不可修改:
unmodifiableCollection(Collection<? extends T> c)
,unmodifiableList(List<? extends T> list)
,unmodifiableSet(Set<? extends T> s)
,unmodifiableMap(Map<? extends K,? extends V> m)
(用于创建不可修改的集合)
五、迭代器 (Iterator)
-
Iterator<E>
接口: 用于遍历集合中的元素。hasNext()
: 判断是否还有下一个元素。next()
: 返回下一个元素。remove()
: 删除迭代器最后一次返回的元素 (可选操作,并非所有迭代器都支持)。
-
ListIterator<E>
接口:List
接口特有的迭代器,支持双向遍历,并可以修改列表。hasPrevious()
: 判断是否还有上一个元素。previous()
: 返回上一个元素。nextIndex()
: 返回下一个元素的索引。previousIndex()
: 返回上一个元素的索引。set(E e)
: 替换迭代器最后一次返回的元素。add(E e)
: 在迭代器当前位置插入一个元素。
-
增强 for 循环 (for-each 循环): 简化了集合的遍历. 本质上是使用了 Iterator.
List<String> list = Arrays.asList("a", "b", "c"); for (String s : list) { System.out.println(s); }
六、泛型 (Generics)
- 集合框架广泛使用了泛型,可以指定集合中存储的元素类型,提高类型安全性和代码可读性。
- 例如:
List<String>
表示一个只能存储String
类型元素的列表。 - 泛型的好处:
- 类型安全: 在编译时检查类型错误,避免运行时类型转换异常。
- 代码可读性: 代码更清晰,更容易理解。
- 代码复用: 可以编写更通用的代码,处理不同类型的集合。
七、并发集合 (Concurrent Collections)
java.util.concurrent
包提供了一组线程安全的集合类,用于多线程环境:
ConcurrentHashMap
: 线程安全的HashMap
。CopyOnWriteArrayList
: 线程安全的List
,适用于读多写少的场景。CopyOnWriteArraySet
: 线程安全的Set
,适用于读多写少的场景。ConcurrentLinkedQueue
: 线程安全的无界队列。ConcurrentLinkedDeque
: 线程安全的无界双端队列。- 阻塞队列 (BlockingQueue):
ArrayBlockingQueue
,LinkedBlockingQueue
,PriorityBlockingQueue
,DelayQueue
,SynchronousQueue
八、最佳实践
-
选择合适的集合类型: 根据你的需求选择最合适的集合接口和实现类。 考虑以下因素:
- 是否需要有序?
- 是否允许重复元素?
- 是否需要根据键查找值?
- 是否需要线程安全?
- 插入、删除、查找的频率?
-
使用泛型: 始终使用泛型来指定集合中存储的元素类型,提高类型安全性。
-
面向接口编程: 使用接口类型(例如
List
,Set
,Map
)声明变量,而不是使用具体的实现类类型。 -
使用增强 for 循环: 优先使用增强 for 循环遍历集合,代码更简洁。
-
注意并发问题: 在多线程环境下,使用线程安全的集合类,或者使用同步机制来保护非线程安全的集合。
-
避免在迭代过程中修改集合: 在使用迭代器遍历集合时,不要直接修改集合的结构(例如添加或删除元素),否则可能会抛出
ConcurrentModificationException
。 可以使用迭代器的remove()
方法删除元素,或者使用ListIterator
修改列表。 -
了解集合的性能特征: 不同的集合实现类具有不同的性能特征,了解这些特征可以帮助我们选择最合适的集合。
-
使用
Collections
工具类: 充分利用Collections
工具类提供的各种静态方法,简化集合操作。 -
合理设置集合的初始容量: 对于
ArrayList
、HashMap
等基于数组的集合,在创建时指定一个合适的初始容量,可以减少扩容操作,提高性能。 -
注意 null 值: 一些集合 (例如
HashMap
,ArrayList
) 允许null值, 一些集合 (例如TreeMap
,Hashtable
) 不允许。
总结
Java 集合框架是 Java 编程中非常重要的一个部分,它提供了一组强大、灵活、高效的工具来处理对象集合。