目录
[三、Java 中不同集合类的性能的比较](#三、Java 中不同集合类的性能的比较)
[(一)、ArrayList 和 LinkedList](#(一)、ArrayList 和 LinkedList)
[(二)、HashSet、LinkedHashSet 和 TreeSet](#(二)、HashSet、LinkedHashSet 和 TreeSet)
[(三)、HashMap、LinkedHashMap 和 TreeMap](#(三)、HashMap、LinkedHashMap 和 TreeMap)
[(四)、Vector 和 ArrayList](#(四)、Vector 和 ArrayList)
Collections.singletonXXX()和Collections.emptyXXX():
Java 集合框架是为了表示和操作 一组对象而设计的统一体系结构。它提供了一组接口和实现类,使得开发者可以方便地存储、检索和操作数据集合。


一、主要接口及 实现类的特点
(1)Collection接口:
这是集合框架的根接口 ,它代表一组对象,称为元素。
子接口有**List、Set和Queue**等。
(2)List接口:
是一个有序 的集合,可以包含重复的元素。
允许通过索引 访问元素,支持随机访问。
常见的实现类有ArrayList、LinkedList和Vector。
1.ArrayList:
基于动态数组实现,随机访问元素速度快。
插入和删除元素在中间位置时效率较低,因为需要移动后续元素。
2.LinkedList:
基于双向链表实现。
插入和删除元素速度快,特别是在列表中间位置。
随机访问元素相对较慢,需要遍历链表。
3.Vector:
与ArrayList类似,但线程安全,性能相对较低。
4.Stack:
它是一种特殊的Vector,实现了后进先出(LIFO)的数据结构。
提供了push(入栈)、pop(出栈)、peek(查看栈顶元素)等方法。
(3)Set接口:
集合中的元素不能重复。
不保证 元素的存储顺序。
常见的实现类有HashSet、LinkedHashSet和TreeSet。
1.HashSet:
使用哈希表实现。
元素的存储顺序取决于哈希值,不保证顺序。
查找元素速度快。
2.LinkedHashSet:
维护了元素的插入顺序。
同时具有哈希表的快速查找和链表的顺序特性。
3.TreeSet:
基于红黑树实现,元素自动排序。
不允许插入重复元素。
4.EnumSet:
是一个专门为枚举类型设计的集合类。
内部使用位向量实现,非常高效,并且只能存储同一枚举类型的元素。
5.CopyOnWriteArraySet:
是一个线程安全的集合类,适用于读多写少的并发场景。
内部使用CopyOnWriteArrayList实现,在进行写操作时会创建一个新的副本,避免了并发修改的问题。
(4)Queue接口:
用于模拟队列 数据结构,遵循**先进先出(FIFO)**原则。
常见的实现类有LinkedList(可作为队列使用)、PriorityQueue等。
Deque
在 Java 中,Deque是一个双端队列接口 ,它既可以作为队列使用(先进先出,FIFO),也可以作为栈使用(后进先出,LIFO)。ArrayDeque和LinkedList是实现Deque接口的两个常用类。
一、ArrayDeque
-
底层数据结构:
ArrayDeque是基于可变数组实现的。它在内部使用一个数组来存储元素,并通过调整数组的大小来适应元素的增加和减少。
-
性能特点:
- 随机访问元素的性能较好,因为可以通过索引直接访问数组中的元素,时间复杂度为 O (1)。
- 在两端添加或删除元素的性能也很高,通常为 O (1) 时间复杂度。但是,在中间位置添加或删除元素可能需要移动大量元素,时间复杂度为 O (n),其中 n 是队列中的元素数量。
-
适用场景:
- 当需要高效地在两端进行添加和删除操作,并且对随机访问有一定需求时,
ArrayDeque是一个不错的选择。例如,可以用作栈或队列来处理数据。
- 当需要高效地在两端进行添加和删除操作,并且对随机访问有一定需求时,
二、LinkedList
-
底层数据结构:
LinkedList是基于双向链表实现的。每个元素都包含指向前一个元素和后一个元素的指针。
-
性能特点:
- 在两端添加或删除元素的性能非常高,时间复杂度为 O (1),因为只需要调整几个指针即可。
- 随机访问元素的性能较差,需要从头或尾开始遍历链表,时间复杂度为 O (n)。
-
适用场景:
- 当需要频繁地在两端进行添加和删除操作,并且对随机访问的需求较少时,
LinkedList很适合。它也可以用作栈、队列或双向链表来处理数据。
- 当需要频繁地在两端进行添加和删除操作,并且对随机访问的需求较少时,
三、PriorityQueue:
基于优先级堆实现的无界队列。
元素按照优先级进行排序,优先级高的元素先出队。
总结:
如果需要高效的随机访问以及两端的快速添加和删除操作,可以考虑使用ArrayDeque。如果更注重两端操作的极致性能,并且对随机访问要求不高,可以选择LinkedList。在实际应用中,可以根据具体的需求场景来选择合适的实现类。
(5)Map接口:
存储键值对,每个键都是唯一的。
常见的实现类有HashMap、LinkedHashMap、TreeMap等。
1.HashMap:
基于哈希表实现,存储键值对。
允许一个键为null,多个值为null。
查找、插入和删除操作效率高。
2.LinkedHashMap:
维护了键值对的插入顺序。
同时具有哈希表的高效性和链表的顺序性。
3.TreeMap:
基于红黑树实现,键自动排序。
不允许键重复。
4.WeakHashMap:
其中的键是弱引用。当垃圾回收器回收某个键所对应的对象时,这个键值对会自动从WeakHashMap中被移除。
适用于需要在内存紧张时自动清理不再使用的键值对的场景。
5.IdentityHashMap:
使用引用相等(==)而不是对象相等(equals方法)来判断键和值的相等性。
在某些需要区分不同对象实例的场景下可能会有用。
6.SortedMap:
此接口扩展了Map接口,保证了键的有序性。
提供了一些方法来获取键的范围,例如subMap、headMap和tailMap方法,可以返回一个子映射,包含指定范围内的键值对。
7.NavigableMap:
进一步扩展了SortedMap接口。
提供了更强大的导航方法,如lowerEntry、floorEntry、ceilingEntry和higherEntry,用于查找与给定键最接近的键值对。
8.Hashtable:
是一个古老的实现类,类似于HashMap,但它是线程安全的。
不允许键或值为null。
由于需要同步机制,性能相对较低。
9.ConcurrentHashMap:
线程安全的哈希表实现,允许多个线程同时进行读写操作,而不需要外部同步。
采用了分段锁技术,提高了并发性能。
(6)接口与实现类的关系
接口定义了一组规范和方法,而实现类则具体实现了这些接口,提供了实际的功能。开发者可以根据具体的需求选择合适的接口和实现类。例如,如果需要一个有序的、可重复的集合,可以选择List接口的实现类ArrayList或LinkedList;如果需要一个不重复的集合,可以选择Set接口的实现类。这种设计模式使得代码具有更好的可扩展性和可维护性,因为可以在不修改现有代码的情况下,切换不同的实现类来满足不同的需求。
三、Java 中不同集合类的性能的比较
在 Java 中,不同的集合类在性能方面有各自的特点。以下是对一些常见集合类的性能比较:
(一)、ArrayList 和 LinkedList
-
随机访问性能:
ArrayList基于动态数组实现,支持快速的随机访问。通过索引访问元素的时间复杂度为 O (1)。LinkedList基于双向链表实现,随机访问需要遍历链表,时间复杂度为 O (n),其中 n 是链表的长度。
-
插入和删除性能:
- 在列表中间位置插入和删除元素时,
LinkedList性能更好。因为它只需要调整相邻节点的指针,时间复杂度为 O (1)。而ArrayList需要移动后续元素,时间复杂度为 O (n)。 - 在列表末尾插入元素时,两者性能相近。
- 在列表中间位置插入和删除元素时,
(二)、HashSet、LinkedHashSet 和 TreeSet
-
添加和查找性能:
HashSet使用哈希表实现,添加和查找元素的时间复杂度通常接近 O (1),在哈希冲突较多时性能会下降。LinkedHashSet在HashSet的基础上维护了元素的插入顺序,性能略低于HashSet。TreeSet基于红黑树实现,添加和查找元素的时间复杂度为 O (log n)。它自动对元素进行排序,适用于需要有序集合的场景。
-
内存占用:
HashSet和LinkedHashSet通常比TreeSet占用更少的内存,因为红黑树需要额外的空间来维护树的结构。
(三)、HashMap、LinkedHashMap 和 TreeMap
-
插入、查找和删除性能:
HashMap基于哈希表实现,插入、查找和删除操作的时间复杂度通常接近 O (1)。LinkedHashMap在HashMap的基础上维护了键值对的插入顺序,性能略低于HashMap。TreeMap基于红黑树实现,插入、查找和删除操作的时间复杂度为 O (log n)。它自动对键进行排序,适用于需要有序键值对的场景。
-
遍历性能:
LinkedHashMap和TreeMap在遍历顺序上有特定的保证,而HashMap的遍历顺序是不确定的。如果需要按照特定顺序遍历集合,LinkedHashMap和TreeMap可能更合适。
(四)、Vector 和 ArrayList
- 线程安全性能:
Vector是线程安全的,在多线程环境下可以直接使用,但由于需要同步机制,性能相对较低。ArrayList不是线程安全的,在多线程环境下需要额外的同步措施。如果不需要线程安全,ArrayList性能更好。
总体而言,选择集合类时需要根据具体的应用场景来考虑性能需求。如果需要快速的随机访问,可以选择ArrayList或HashMap;如果需要频繁的插入和删除操作,可以考虑LinkedList或LinkedHashMap;如果需要有序集合,可以选择TreeSet或TreeMap。同时,还需要考虑线程安全等其他因素。
四、集合类的工具类
Arrays.asList():
- 可以将数组转换为
List视图。 - 这个视图是固定大小的,不能进行添加或删除元素的操作,但可以进行修改元素的操作。
Collections.singletonXXX()和Collections.emptyXXX():
singletonXXX方法可以创建只包含一个元素的不可变集合,如singletonList、singletonSet等。emptyXXX方法可以创建空的不可变集合,如emptyList、emptySet等。
这些集合类在不同的场景下提供了丰富的选择,以满足各种数据存储和操作的需求。
五、Map和Collection接口联系:
(一)、都是集合框架的一部分
- 共同构成集合体系:
Map和Collection接口都是 Java 集合框架中的核心接口,它们一起为开发者提供了丰富的数据存储和操作方式。- 集合框架旨在提供统一的方式来处理不同类型的数据集合,无论是存储单个元素的集合(如
List、Set等)还是存储键值对的映射(如Map)。
(二)、可以相互转换
-
Map转Collection:- 可以通过
Map的方法获取其键集(keySet)、值集(values)或键值对集合(entrySet),这些集合都是Collection的子接口的实现。 - 例如,通过
map.keySet()可以得到一个包含Map中所有键的Set集合,这个集合可以进行迭代、添加或删除元素等操作,就像其他普通的Collection集合一样。
- 可以通过
-
Collection转Map:- 在某些情况下,可以将一个包含特定类型元素的
Collection转换为Map。例如,可以使用 Java 8 的流(Stream)和Collectors.toMap方法将一个包含特定对象的列表转换为一个Map,其中对象的某个属性作为键,对象本身作为值。
- 在某些情况下,可以将一个包含特定类型元素的
(三)、在某些操作上有相似性
-
遍历方式:
- 虽然
Map和Collection的内部结构不同,但它们都可以通过迭代器进行遍历。 - 对于
Collection,可以直接使用迭代器遍历集合中的元素。对于Map,可以通过遍历其键集、值集或键值对集合来间接遍历Map中的内容。
- 虽然
-
一些通用方法:
- 部分集合框架的工具类方法可以同时应用于
Map和Collection。例如,Collections类中的一些排序、查找等方法可以应用于List等Collection实现类,而在某些情况下,也可以通过将Map的键集或值集转换为Collection后应用这些方法。
- 部分集合框架的工具类方法可以同时应用于
总体而言,Map和Collection接口在 Java 集合框架中既有区别又有联系,它们共同为开发者提供了灵活多样的数据处理方式。