【Java】说HashMap链表长度超过8就会转换成红黑树的出来挨打!

  • 先上结论:在极限情况下,某一个位置链表长度达到11时,才会转换成红黑二叉树结构。
  • 这个极限情况指的是每次都是因为某个位置链表长度而导致的数组扩容,比如说数据只向数组中一个位置添加数据。
  • 网上很多人说jdk1.8后HashMap链表长度超过8就会转换成红黑树,通过源码阅读和测试后已经可以确定并不是超过8个就变红黑树,链表长度超过8,只是会尝试转换为二叉树,转换前,首先判断数组容量是否足够大,如果不够大,则进行扩容,发现长度小(未达到64),则扩容为原来的2倍,如果达到64,假设数组某个位置链表长度已经为10,如果这个位置还有entry进来即为11个时,才变成红黑树!具体验证过程如下:
验证方式:通过debug的方式查看实际的过程。
具体的过程如下:
   	1.前提,向hashmap中添加数据,只让数据只向集合数组中的同一个位置进行添加。
   		如何保证数据只向数组中同一个索引位置添加数据呢?
   	 	a、对key进行hashcode,然后再和(length-1)进行 & 运算,结果相同的数据进入数组中同一位置;
   	 	b、如果key的hashcode不同只是分配位置相同,则直接添加进链表,如果hashcode相同则通过equals()方法进行比较以分辨key是否真的重复(hashcode相同key不一定同)
   	 	c、hashcode值相同通过调用key中equals()方法比较新增数据和原数组位置的链表数据key是否重复,不重复则添加成功,重复则替换;
   	 	所以我们的测试程序只要保证每个数据key的hashcode相同,equals()方法的返回值保持不同即可。
   	2.具体过程源码分析及现象
   		a、当hashmap某一个位置,链表数据的个数超过8个(即当有9个时),会尝试转换为二叉树;
   		b、转换前,首先判断数组容量是否足够大,如果不够大,则进行扩容,发现16长度小,则扩容为原来的2倍,数组的长度16*2=32;
   		c、添加第10个数据时,同样尝试转换为二叉树,转换前,发现32长度还较少,则继续扩容,此时数组的长度为32*2=64;
   		d、添加第11个数据时,同样尝试转换为二叉树,转换前,发现64长度已经不少了,则将链表转换为红黑树。
  • 其他相关问题
    问题:通过源码阅读后发现HashMap底层和很多框架一样也是用相与的方式进行数据位置的分配,此时为什么要用2的整数倍进行扩容呢?
    答:之所以是2的整数倍进行扩容是因为底层用的与运算而不是取余,为了在与hash进行与运算的时候,使每个位置都有机会被分配,如果不是2的整数倍与运算时便会有位置为固定为0,结果不可能是1,导致扩容后有位置没有数据的进入,我们以“book”的Key来演示整个过程,具体分析过程如下
与运算公式如下(Length是HashMap的长度):
	                      index = HashCode(Key) & (Length - 1)
	1.计算book的hashcode,结果为十进制的3029737,二进制的1011100011101011101001。
	2.假定HashMap长度是默认的16,计算Length-1的结果为十进制的15,二进制的1111。
	3.把以上两个结果做与运算,101110001110101110 1001 & 1111 = 1001,十进制是9,所以 index=9。
	可以说,Hash算法最终得到的index结果,完全取决于Key的Hashcode值的最后几位。
	假设HashMap的长度是10,重复刚才的运算步骤: 

在这里插入图片描述

	单独看这个结果,表面上并没有问题。
	我们再来尝试一个新的HashCode 101110001110101110 1011

在这里插入图片描述

  • 虽然HashCode的倒数第二第三位从0变成了1,但是运算的结果都是1001。也就是说,当HashMap长度为10的时候,有些index结果的出现几率会更大,而有些index结果永远不会出现,比如1111,那么这个位置扩容后将一直没有数据进入。这样显然不符合Hash算法均匀分布的原则。反观长度16或者其他2的幂,Length-1的值是所有二进制位全为1,这种情况下,index的结果等同于HashCode后几位的值。只要输入的HashCode本身分布均匀,Hash算法的结果就是均匀的。
  • 10
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值