ArrayList和LinkedList的底层原理以及HashMap的扩容机制

一、ArrayList

ArrayList作为List的主要实现类;线程不安全,效率高;底层使用数组实现。

由于其地址的连续性,导致长度固定,类型固定,从而使得其灵活性不足,删除和插入性能低下

原理:当一个ArrayList初次创建出来时,他在内存中的长度为0,一旦它里面添加里数据,那它的长度将变为10,随着数据的增加,当它的无法再存放数据时,它会生成一个新的数组,新的数组将变成它原来的1.5倍,而旧数组的数据将通过.copyOf()的方法转移到新的数组当中,旧的数组则被垃圾回收器回收。

优点:底层基于数组,查找数据是通过下标进行查找,所以它查找效率高

缺点:由于它本身在增删时会自动进行元素位移,保证不会留空,所以随着它的数据量的增多,他的增删效率也会随着变低。

二、LinkedList

LinkedList底层使用双向链表

在我们了解双向链表之前,我们需要先了解什么是单向链表

单向链表:链表结构是由一个一个的节点组成,一个节点由数据值和下一个元素的地址组成。

双向链表:链表结构中除了头节点和尾节点的每个节点都包含当前元素的值以及指向前一个节点和后一个节点的引用。头节点中包含first,当前元素值以及指向后一个节点的引用;尾节点中包含指向前一个节点的引用,当前元素值以及last。

基于这样特殊的数据结构,使得它增删变得非常简单,比如,当我们想要删除某个节点时,只需要修改其相邻两个节点的指针指向就可以了。

但是缺点也有:当我们需要查找某个数据时,会默认从头到尾挨个去进行查询。

三、HashMap

HashMap的底层有数组 + 链表(红黑树)组成,数组的大小可以在构造方法时设置,默认大小为16,数组中每一个元素都可以存放一个或多个(entry),就是一个链表,jdk7之前链表中的元素采用头插法插入元素,jdk8之后采用尾插法插入元素,由于插入的元素越来越多,查找效率就变低了,所以满足某种条件时,链表会转换成红黑树。随着元素的增加,HashMap的数组会频繁扩容,如果构造时不赋予加载因子默认值,那么负载因子默认值为0.75,数组扩容的情况如下:

1:当添加某个元素后,数组的总的添加元素数大于了 数组长度 * 0.75(默认,也可自己设定),数组长度扩容为原来的两倍。(如开始创建HashMap集合后,数组长度为16,临界值为16 * 0.75 = 12,当加入元素后元素个数超过12,数组长度扩容为32,临界值变为24)

2:在没有红黑树的条件下,添加元素后数组中某个链表的长度超过了8,数组会扩容为两倍.(如开始创建HashMAp集合后,假设添加的元素都在一个链表中,当链表中元素为8时,再在链表中添加一个元素,此时若数组中不存在红黑树,则数组会扩容为两倍变成32,假设此时链表元素排列不变,再在该链表中添加一个元素,数组长度再扩容两倍,变为64,假设此时链表元素排列还是不变,则此时链表中存在10个元素,这是HashMap链表元素数存在的最大值,此时,再加入元素,满足了链表树化的两个条件(1:数组长度达到64, 2:该链表长度达到了8),该链表会转换为红黑树。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值