Java Collections Framework 是Java 编程语言的核心部分之一。几乎所有编程语言都使用集合。大多数编程语言都支持各种类型的集合,例如List、Set、Queue、Stack等。
什么是Java集合框架?
Java中的集合,又叫容器。它是一个对象。就像将多个项目组合在一个单元中的容器。例如,一罐巧克力、一个名字列表等。
集合在每一种编程语言中都有使用,当 Java 出现时,它也附带了几个集合类—— Vector、Stack、Hashtable、Array。
Java 1.2 提供了集合框架,该框架是在 Java 中以标准方式表示和操作集合的架构。Java 集合框架由以下部分组成:
1、接口
Java Collections Framework 接口提供抽象数据类型来表示集合。
java.util.Collection
是集合框架的根接口。它位于集合框架层次结构的顶部。包含了一些重要的方法,例如每个 Collection
类都必须实现的 size()
、iterator()
、add()
、remove()
、clear()
。
其他一些重要的接口是 java.util.List
、java.util.Set
、java.util.Queue
和 java.util.Map
。
Map 是唯一不继承自 Collection 接口的接口,但它是 Collections 框架的一部分。所有集合框架接口都存在于 java.util 包中。
2、实现类
Java Collections
框架为核心集合接口提供了实现类。我们可以使用它们在 Java 程序中创建不同类型的集合。
一些重要的集合类是 ArrayList
、LinkedList
、HashMap
、TreeMap
、HashSet
和 TreeSet
。
这些类解决了我们大部分的编程需求,但是如果我们需要一些特殊的集合类,我们可以通过扩展它们来创建我们的自定义集合类。
Java 1.5 提出了线程安全的集合类,允许我们在迭代它们时修改集合。其中一些是 CopyOnWriteArrayList
、ConcurrentHashMap
、CopyOnWriteArraySet
。这些类在 java.util.concurrent
包中。
所有集合类都存在于 java.util
和 java.util.concurrent
包中。
3、算法
算法是提供一些常见功能(例如搜索、排序和改组)的有用方法。
集合框架类图
下面的类图显示了集合框架层次结构。为简单起见,我只包含了常用的接口和类。
Java集合框架的好处
Java Collections 框架具有以下优点:
- 减少开发工作量——它带有几乎所有常见类型的集合和有用的方法来迭代和操作数据。所以我们可以更专注于业务逻辑,而不是设计我们的集合 API。
- 更好的质量——使用经过充分测试的核心集合类可以提高我们的程序质量,而不是使用任何自己开发的数据结构。
- 可重用性和互操作性
- 减少维护工作,因为每个人都知道 Collection API 类。
Java 集合 API 接口
Java 集合接口是 Java 集合框架的基础。请注意,所有核心集合接口都是通用的;例如公共接口 Collection
1、Collection 接口
这是集合的根。集合表示一组称为其元素的对象。Java 平台不提供此接口的任何直接实现。
可以通过它的size
,isEmpty
去查看集合中有多少元素,检查是否包含某个元素(contains
),从集合中添加和删除元素(add, remove
),以及在集合上提供迭代器(iterator)。
Collection 接口还提供了对整个集合批量操作的方法——containsAll
、addAll
、removeAll
、retainAll
、clear
。
toArray
方法是作为集合和数组转换的桥梁而提供的。
2、Iterator接口
Iterator 接口提供了迭代 Collection 元素的方法。我们可以使用iterator()
方法获取迭代器的实例。迭代器取代了Enumeration
Java 集合框架中的 。迭代器允许调用者在迭代期间从底层集合中删除元素。集合类中的迭代器实现了 迭代器设计模式。
3、Set接口
Set 是一个不能包含重复元素的集合。此接口对数学集合抽象进行建模,并用于表示集合,例如一副纸牌。
Java平台包含三个通用Set实现:HashSet
,TreeSet
,和LinkedHashSet
。
Set 接口不允许随机访问 Collection 中的元素。您可以使用迭代器或 foreach 循环来遍历 Set 的元素。
4、List 接口
List是一个有序集合,可以包含重复的元素。
可以从其索引访问任何元素。
列表更像是具有动态长度的数组。列表是最常用的集合类型之一。ArrayList
和LinkedList
是 List 接口的实现类。
List 接口提供了很多方法方法,比如在特定索引处添加元素、根据索引删除/替换元素以及使用索引获取子列表。
List strList = new ArrayList<>();
//add at last
strList.add(0, "0");
//add at specified index
strList.add(1, "1");
//replace
strList.set(1, "2");
//remove
strList.remove("1");
Collections 类为 List 提供了一些有用的算法——排序(sort)、打乱(shuffle)、翻转(reverse)、搜索指定列表(binarySearch )等。
5、Queue接口
Queue接口与List、Set同一级别,都是继承了Collection接口。Queue集合在集合的基础上添加了增删改查操作,并且队列默认使用FIFO(先进先出)规则进行排序
例外情况是优先级队列,它根据提供的比较器或元素的自然顺序对元素进行排序。无论使用何种顺序,队列的头部都是将通过调用 remove 或 poll 删除的元素。在 FIFO 队列中,所有新元素都插入到队列的尾部。
6、Dequeue 接口
是一个双端队列,支持两端元素插入和移除的线性集合。名称 deque 是“双端队列”的缩写,通常发音为“deck”。大多数 Deque 实现对它们可能包含的元素数量没有固定限制,但此接口支持容量受限的双端队列以及没有固定大小限制的双端队列。
该接口定义了访问双端队列两端元素的方法。提供了插入、删除和检查元素的方法。
7、Map接口
Map是一个将键映射到值的对象。映射不能包含重复的键:每个键最多可以映射到一个值。
Java 平台包含三个通用的 Map 实现:HashMap、TreeMap 和 LinkedHashMap。
Map的基本操作有put、get、containsKey、containsValue、size、isEmpty。
8、ListIterator 接口
列表的迭代器,允许程序员沿任一方向遍历列表,在迭代期间修改列表,并获取迭代器在列表中的当前位置。
Java ListIterator没有当前元素;它的光标位置始终位于调用 previous() 返回的元素和调用 next() 返回的元素之间。
9、 SortedSet 接口
SortedSet 是一个按升序维护其元素的 Set。
提供了几个额外的操作来利用排序。排序集用于自然排序的集,例如单词列表和成员列表。
10、SortedMap 接口
按键升序维护其映射的映射。
这是 SortedSet 的 Map 模拟。排序映射用于键/值对的自然排序集合,例如字典和电话簿。
Java 集合类
Java Collections 框架带有许多接口的实现类。最常见的实现是ArrayList
、HashMap
和 HashSet
。
Java 1.5 包含并发实现;例如 ConcurrentHashMap
和 CopyOnWriteArrayList
。
通常 Collection
类不是线程安全的,它们的迭代器是快速失败的。在本节中,我们将了解常用的集合类。
1、HashSet 类
Java HashSet是由HashMap支持的 Set 接口的基本实现。它不保证集合的迭代顺序并允许空元素。
此类为基本操作(add
、remove
、contains
和size
) ,它不保证集合的迭代顺序; 特别是,它不保证订单会随着时间的推移保持不变。 此类允许null元素。
假设散列函数将元素正确地分散到存储桶中。我们可以为这个集合设置初始容量和负载因子。负载因子是衡量哈希映射在其容量自动增加之前允许获得多满的度量。
2、TreeSet类
TreeSet
是JAVA中集合的一种,TreeSet
是一个有序的集合,它的作用是提供有序的Set集合。它继承于AbstractSet
抽象类,实现了NavigableSet<E>
,Cloneable,java.io.Serializable
接口。
一个NavigableSet
基于一个实现TreeMap
。根据使用的Comparator
构造函数,元素使用它们的自然顺序进行排序,或者通过在集合创建时提供的顺序进行排序。
此实现为基本操作(添加、删除和包含)提供有保证的 log(n) 时间成本。
请注意,如果要正确实现 Set 接口,则集合维护的排序(无论是否提供显式比较器)必须与 equals 一致。
这是因为 Set 接口是根据 equals 操作定义的,但是 TreeSet 实例使用它的 compareTo(或 compare)方法执行所有元素比较,所以两个被此方法视为相等的元素,从集合的角度来看,是相等的。
3、ArrayList 类
Java ArrayList是 List 接口的可调整大小的数组实现。
实现所有可选的列表操作,并允许所有元素,包括 null。
除了实现 List 接口之外,该类还提供了操作内部用于存储列表的数组大小的方法。(这个类大致相当于 Vector,只是它是不同步的。)
size
、isEmpty
、get
、set
、iterator
和 list
迭代器操作在恒定时间内运行。add 操作在分摊常数时间内运行,即添加 n 个元素需要 O(n) 时间。所有其他操作都在线性时间内运行(粗略地说)。与 LinkedList 实现相比,常量因子较低。
4、 LinkedList 类
LinkedList
也是List
接口的实现类,与ArrayList
不同之处是采用的存储结构不同,ArrayList
的数据结构为线性表,而LinkedList
数据结构是链表。
链表数据结构的特点是每个元素分配的空间不必连续、插入和删除元素时速度非常快、但访问元素的速度较慢。
List 和 Deque 接口的双向链表实现。实现所有可选的列表操作,并允许所有元素(包括空值)。
对于双向链表,所有操作都按预期执行。索引到列表中的操作将从开始或结束遍历列表,以更接近指定索引的为准。
5、HashMap 类
Map接口基于哈希表的实现。
此实现提供所有可选的映射操作并允许空值和空键。HashMap 类大致等同于 Hashtable,只是它是不同步的并且允许为 null。此类不保证Map的顺序。
此实现为基本操作(get
和put
)提供恒定时间性能。它提供构造函数来设置集合的初始容量和负载因子。
6、 TreeMap 类
基于红黑树的 NavigableMap 实现。
映射根据其键的自然顺序进行排序,或者通过映射创建时提供的 Comparator 进行排序,具体取决于使用的构造函数。
此实现为 containsKey、get、put 和 remove 操作提供有保证的 log(n) 时间成本。算法是对 Cormen、Leiserson 和 Rivest 的算法简介中的算法的改编。
请注意,TreeMap 维护的顺序,与任何排序映射一样,无论是否提供显式比较器,如果此排序映射要正确实现 Map 接口,则必须与 equals 一致。
之所以如此,是因为 Map 接口是根据 equals 操作定义的,但排序映射使用其 compareTo(或 compare)方法执行所有键比较,因此两个从排序映射的角度来看,此方法认为相等的键是相等的。
有序映射的行为是明确定义的,即使它的排序与 equals 不一致;它只是不遵守 Map 接口的一般约定。
7. PriorityQueue 类
队列按 FIFO 顺序处理其元素,但有时我们希望根据元素的优先级来处理元素。
在这种情况下我们可以使用 PriorityQueue 并且我们需要在实例化 PriorityQueue 时提供 Comparator 实现。
PriorityQueue 不允许空值并且它是无界的。
集合类
Java Collections 类只包含对集合进行操作或返回集合的静态方法。它包含对集合进行操作的多态算法、“包装器”,它返回一个由指定集合支持的新集合,以及一些其他零碎的东西。
该类包含集合框架算法的方法,例如二分查找、sorting、shuffling, reverse, etc.
同步包装器
同步包装器将自动同步(线程安全)添加到任意集合。
六个核心集合接口(Collection、Set、List、Map、SortedSet 和 SortedMap)中的每一个都有一个静态工厂方法。
public static Collection synchronizedCollection(Collection c);
public static Set synchronizedSet(Set s);
public static List synchronizedList(List list);
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m);
public static SortedSet synchronizedSortedSet(SortedSet s);
public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m);
这些方法中的每一个都返回由指定集合备份的同步(线程安全)集合。
不可修改的包装器
不可修改的包装器通过拦截所有会修改集合的操作并抛出一个UnsupportedOperationException
. 它的主要用途是;
- 使集合在构建后不可变。在这种情况下,最好不要维护对后备集合的引用。这绝对保证了不变性。
- 允许某些客户端只读访问您的数据结构。您保留对支持集合的引用,但分发对包装器的引用。这样,客户端可以查看但不能修改,而您保持完全访问权限。
public static Collection unmodifiableCollection(Collection<? extends T> c);
public static Set unmodifiableSet(Set<? extends T> s);
public static List unmodifiableList(List<? extends T> list);
public static <K,V> Map<K, V> unmodifiableMap(Map<? extends K, ? extends V> m);
public static SortedSet unmodifiableSortedSet(SortedSet<? extends T> s);
public static <K,V> SortedMap<K, V> unmodifiableSortedMap(SortedMap<K, ? extends V> m);
线程安全集合类
Java 1.5 并发包 ( java.util.concurrent
) 包含线程安全的集合类,允许在迭代时修改集合。
按照设计,迭代器是快速失败的并抛出 ConcurrentModificationException。其中一些类是CopyOnWriteArrayList
、ConcurrentHashMap
、CopyOnWriteArraySet
。