JAVA中的集合知识点

本文详细介绍了JAVA中的Collection和Map接口,包括Set(如TreeSet,HashSet,LinkedHashSet)、List(如ArrayList,Vector,LinkedList)和Queue(如LinkedList,PriorityQueue)的特性及其实现。重点讲解了扩容机制,如ArrayList和HashMap的动态扩容策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JAVA中的集合主要又Collection和Map两个接口组成。其中Collection包括Set、List、Queue三个实现类,而Map接口包含TreeMap、HashMap、HashTable等实现类。下面是主要介绍。

1、Collection接口

1.1 Set接口

1. SetTreeSet:基于红⿊树实现,⽀持有序性操作,例如:根据⼀个范围查找元素的操作。但是查找效率不如 HashSet,HashSet 查找的时间复杂度为 O(1),TreeSet 则为 O(logN)。

2. HashSet:基于哈希表实现,⽀持快速查找,但不⽀持有序性操作。并且失去了元素的插⼊顺序信息,也就是 说使⽤ Iterator 遍历 HashSet 得到的结果是不确定的。

3. LinkedHashSet:具有 HashSet 的查找效率,且内部使⽤双向链表维护元素的插⼊顺序。

1.2 List接口

1. ArrayList:基于动态数组实现,⽀持随机访问。

2. Vector:和 ArrayList 类似,但它是线程安全的。

3. LinkedList:基于双向链表实现,只能顺序访问,但是可以快速地在链表中间插⼊和删除元素。不仅如此, LinkedList 还可以⽤作栈、队列和双向队列。

1.3 Queue接口

1. LinkedList:可以⽤它来实现双向队列。

2. PriorityQueue:基于堆结构实现,可以⽤它来实现优先队列。

2、Map接口

1. TreeMap:基于红⿊树实现。

2. HashMap:基于哈希表实现。

3. HashTable:和 HashMap 类似,但它是线程安全的,这意味着同⼀时刻多个线程可以同时写⼊ HashTable 并且不会导致数据不⼀致。它是遗留类,不应该去使⽤它。现在可以使⽤ ConcurrentHashMap 来⽀持线程安全,并且 ConcurrentHashMap 的效率会更⾼,因为 ConcurrentHashMap 引⼊了分段锁。

4. LinkedHashMap:使⽤双向链表来维护元素的顺序,顺序为插⼊顺序或者最近最少使⽤(LRU)顺序

3、关于JAVA集合的知识点

3.1、ArrayList的扩容机制

在具体实现中,ArrayList的扩容机制如下所示:

1、当向ArrayList中添加元素时,首先会检查ArrayList的当前大小(也就是它内部的数组大小)是否能够容纳新的元素。如果可以,那么新元素就直接被添加到ArrayList中。
2、如果ArrayList的当前大小不足以容纳新的元素,那么ArrayList就需要进行扩容操作。在扩容操作中,ArrayList会创建一个新的数组,新数组的大小是原数组大小的1.5倍(也就是原数组大小+原数组大小的一半)。这个1.5倍的值是在JDK的源码中定义的。
3、然后,ArrayList会使用System.arraycopy方法,将原有数组中的所有元素复制到新的数组中。
4、最后,新的数组会替代原有的数组,成为ArrayList的内部数组。
这个扩容机制的优点是,能够让ArrayList动态地适应数据量的变化,使得我们在使用ArrayList时,不需要关心容量问题。但是,扩容操作会消耗一定的性能,因为需要创建新的数组,并复制原有的元素。所以,如果你在创建ArrayList时,已经大致知道最终的数据量,那么可以在创建ArrayList时,指定一个接近最终数据量的初始容量,以减少扩容操作的次数,提高性能。对于ArrayList的无参构造,在添加第一个元素后,ArrayList的容量为10,然后正常扩容。

3.2、HashMap的扩容机制

一般情况下,当元素数量超过阈值时便会触发扩容。每次扩容的容量都是之前容量的2倍。

HashMap的容量是有上限的,必须小于1<<30,即1073741824。如果容量超出了这个数,则不再增长,且阈值会被设置为Integer.MAX_VALUE( 2^31-1,即永远不会超出阈值了)。

HashMap的容量变化通常存在以下几种情况:

1、空参数的构造函数:实例化的HashMap默认内部数组是null,即没有实例化。第一次调用put方法时,则会开始第一次初始化扩容,长度为16。
2、有参构造函数:用于指定容量。会根据指定的正整数找到不小于指定容量的2的幂数,将这个数设置赋值给阈值(threshold)。第一次调用put方法时,会将阈值赋值给容量,然后让 
阈值=容量*负载因子。(因此并不是我们手动指定了容量就一定不会触发扩容,超过阈值后一样会扩容!!)
3、如果不是第一次扩容,则容量变为原来的2倍,阈值也变为原来的2倍。(容量和阈值都变为原来的2倍时,负载因子还是不变)

4、HashMap的底层是数组+链表+红黑树,当数组的某一索引位置上的元素以链表存在的数据个数大于8,且当前数组的长度大于64时,此时索引位置上的所有数据改为红黑树的方式存储。
此外还有几个细节需要注意:

首次put时,先会触发扩容(算是初始化),然后存入数据,然后判断是否需要扩容;
不是首次put,则不再初始化,直接存入数据,然后判断是否需要扩容;

3.3 HashSet的原理

HashSet 的实现是依赖于 HashMap 的,HashSet 的值都是存储在 HashMap 中的。在 HashSet 的构造法中会初 始化⼀个 HashMap 对象,HashSet 不允许值᯿复。因此,HashSet 的值是作为 HashMap 的 key 存储在 HashMap 中的,当存储的值已经存在时返回 false。HashSet的底层为数组+链表。

HashSet在于添加的元素不是按照顺序排列的,而是按照添加的元素的哈希值添加的,所以不支持有序操作。

对于HashSet添加的元素,必须重写hashCode方法和equals()方法,保证元素不能重复。

对于HashSet添加元素的过程主要有接下来几步。

(1)向HashSet中添加元素时,先计算元素的哈希值。

(2)判断哈希值对应的位置有没有元素,没有元素直接添加

(3)如果有元素,使用equals()方法判断是否相等,如果不相等就添加。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值