目录
[三、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 集合框架中既有区别又有联系,它们共同为开发者提供了灵活多样的数据处理方式。