Java集合概述
Java 集合(Collections)是 Java 中提供的一种容器,用于存储和管理多个对象。与数组不同,集合的长度是可变的,且只能存储对象(包括对象的引用),不能存储基本数据类型。集合是 Java 编程中非常重要的一部分,特别是在处理大量数据时,集合提供了丰富的操作方法和灵活的数据结构。
Java集合的体系结构
Java 集合,也叫作容器,主要是由两大接口派生而来:
-  一个是 Collection接口,主要用于存放单一元素
 Collection接口,又有三个主要的子接口:List、Set和Queue
-  另一个是 Map接口,主要用于存放双列数据,保存了具有映射关系的键值对 “key-value” 集合。
![![[Java 集合框架.png]]](https://i-blog.csdnimg.cn/direct/9863bf3a3dcb4bf4a5419a939b403828.png)
 图中只列举了主要的继承派生关系,并没有列举所有关系。如省略了AbstractList, NavigableSet 等抽象类以及其他的一些辅助类。
Collection 接口
Collection接口是构建集合框架的基础,它是单列集合的根接口,定义了集合的基本操作,如添加、删除、遍历等。Collection接口有两个重要的子接口:List 和 Set。List 接口维护元素的顺序,而 Set 接口不允许有重复的元素。
List 接口
List:有序集合(也称为序列),允许元素重复。List接口的主要实现包括ArrayList、Vector和LinkedList。
ArrayList
- 底层实现:ArrayList使用一个动态数组Object[]来存储元素。
- 特点:访问速度快,因为元素存储在连续的内存空间中。插入和删除操作相对较慢,因为它们可能需要移动大量元素。
- 线程安全性:非线程安全,如果多个线程并发访问和修改ArrayList,需要手动同步或使用Collections.synchronizedList。
Vector
- 底层实现:Vector与ArrayList类似,也是使用一个动态数组Object[]来存储元素。
- 特点:Vector与ArrayList的主要区别在于它是线程安全的,因此在多线程环境中使用Vector更加安全。
- 性能:由于 Vector中的方法是同步的,所以在单线程环境中性能不如ArrayList。
LinkedList
- 底层实现:LinkedList使用双向链表来存储元素。在JDK 1.6及以前版本中,LinkedList使用循环双向链表;而在 JDK 1.7 及以后版本中,取消了循环特性。
- 特点:插入和删除操作非常快,因为只需要更新指针即可。但是随机访问较慢,因为需要从头遍历链表。
- 适用场景:适合频繁插入和删除的场景,如实现栈和队列。
Set 接口
Set接口是一个不允许重复元素的集合。它的主要实现包括HashSet、LinkedHashSet和TreeSet。
HashSet
- 底层实现:HashSet基于HashMap实现,实际上它是一个键值对的集合,其中键就是元素本身,值总是PRESENT。
- 特点:不保证集合中元素的顺序,元素的顺序由哈希码决定。
- 线程安全性:非线程安全。
LinkedHashSet
- 底层实现:LinkedHashSet是HashSet的一个子类,它通过LinkedHashMap来实现,因此它维护了一个按插入顺序排列的链表。
- 特点:元素按照插入顺序排序。
- 线程安全性:非线程安全。
TreeSet
- 底层实现:TreeSet使用红黑树(一种自平衡的排序二叉树)来存储元素。
- 特点:自然排序或自定义排序,元素是按升序排序的。
- 线程安全性:非线程安全。
Queue 接口
Queue 接口是一个用于存储元素的集合,也属于 Collection 接口,通常按照先进先出(FIFO)的原则处理元素。Queue接口的主要实现包括PriorityQueue、DelayQueue和ArrayDeque。
PriorityQueue
- 底层实现:PriorityQueue使用Object[]数组来实现小顶堆(最小值在顶部)。
- 特点:队列中的元素会自动排序,最小的元素在队列的头部。
- 线程安全性:非线程安全。
DelayQueue
- 底层实现:DelayQueue是一个特殊的Queue实现,它使用PriorityQueue作为其内部数据结构。
- 特点:队列中的元素是Delayed类型的,只有当延迟到期时,元素才可从队列中取出。
- 线程安全性:非线程安全,但在多线程环境下通常使用ReentrantLock等同步机制。
ArrayDeque
- 底层实现:ArrayDeque使用一个可动态扩展的数组来存储元素。
- 特点:既可以当作栈使用,也可以当作队列使用。
- 线程安全性:非线程安全。
适用场景
选择合适的集合类型取决于具体的应用场景。例如:
-  如果需要一个有序且可重复的集合,可以选择 ArrayList或LinkedList
-  如果需要一个去重的集合,可以选择 HashSet或TreeSet
-  如果需要实现队列的功能,可以选择 PriorityQueue或ArrayDeque。
每种集合都有其特定的优势和适用场景,理解它们的内部实现可以帮助你更好地选择合适的数据结构。
Map 接口
Map (用 key 来搜索的专家): 使用键值对(key-value)存储,key 是无序的、不可重复的,value 是无序的、可重复的,每个键最多映射到一个值。
HashMap
HashMap:JDK1.8 之前 HashMap 由 数组+链表 组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的(“拉链法”解决冲突)。
JDK1.8 以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8)(将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树)时,将链表转化为红黑树,以减少搜索时间。
LinkedHashMap
LinkedHashMap:LinkedHashMap 继承自 HashMap,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成。
LinkedHashMap 在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑。
Hashtable
Hashtable:数组+链表组成的,数组是 Hashtable 的主体,链表则是主要为了解决哈希冲突而存在的。
Hashtable
Hashtable:红黑树(自平衡的排序二叉树),能够根据键的自然顺序或自定义比较器对键进行排序。
为什么选择集合
当需要存储一组类型相同的数据时,数组是最常用且最基本的容器之一。但是,使用数组存储对象存在一些不足之处,在实际开发中,存储的数据类型多种多样且数量不确定。
与数组相比,Java 集合提供了更灵活、更有效的方法来存储多个数据对象。Java 集合框架中的各种集合类和接口可以存储不同类型和数量的对象,同时还具有多样化的操作方式。
相较于数组,Java 集合的优势在于它们的大小可变、支持泛型、具有内建算法等。提高了数据的存储和处理灵活性,可以更好地适应现代软件开发中多样化的数据需求,并支持高质量的代码编写。
如何选用集合
主要根据集合的特点来选择合适的集合。比如:
-  需要 根据键值获取到元素值 时就选用 Map接口下的集合:- 需要排序 时选择 TreeMap
- 不需要排序 时就选择 HashMap
- 需要保证线程安全 就选用 ConcurrentHashMap。
 
- 需要排序 时选择 
-  只需要 存放元素值 时,就选择实现 Collection接口的集合:- 需要保证元素唯一时选择实现 Set接口的集合比如TreeSet或HashSet
- 不需要就选择实现 List接口的比如ArrayList或LinkedList,然后再根据实现这些接口的集合的特点来选用。
 
- 需要保证元素唯一时选择实现 


















