HashMap 面试问题

1.HashMap用什么数据结构实现的?

1.7是数组+链表
1.8是数组+链表,当链表的长度大于8的时候,链表转化成红黑树

2.HashMap初始化传入的容量参数的值就是HashMap实际分配的空间么?

不是。那是什么呢?是比传入容量参数值大的最小的2的n次方,比如传入6,实际分配8。看下计算容量的源码。虽然这里源码计算的值只是threshold,而没有代码说明它是实际值,但本文最后的源码可以说明它就是实际值。
看到这个这个tableSizeFor方法,那么规则的1、2、4、8、16,是不是有点蒙。算法长成这样,是画画么?先了解下基础知识,一个整形由4个字节构成,那它转为二进制应该是32(4*8)位。但这是有符号的,其实正数和负数各占一半,也就是说各有2的31次方,最高位是符号位。我们这里是无符号操作就不用管这个符号了。上面的无符号右移16位就可以覆盖32位,16就是这么来的。其实这5个>>>(无符号右移)是为了把cap-1的最高二进制位及其后面的位都置成1。
最高二进制位是什么意思呢? 一个整形转为二进制后,最左边的那位一定是1,前面补的0不能算哈,这个最左的1就是最高二进制位。
按上面的算法,第一次无符号右移1位再和原二进制按位或,至少把最左边和次最左边的两个位置为1了吧。那第二次再只移一位就没意义了,因为前两位都是1了,不需计算了,所以第二次是右移2位,这样就有4个1了。同理4位变8位,8位变16位,最后16位变32位,实际是只有31位(最前的是符号位)。这样就把cap-1变为一个从其二进制形式的最高位到0位全为1的二进制数了,而这个二进制数正好是比cap-1大一点的那个2的n次方的数-1(如2的3次方减1就是1000-1=0111=7)。
最后一行再+1就是2的n次方了(7+1=8=2的3次方).而第一行的n=cap-1,这也就是防止传入参数就是2的n次的情况(如8的二进制是1000),再把这个最高二进制位的后面都置成1,最后再加1就变成16了。这就不是与传入参数最接近的2的n次方了。
这里也就回答了为什么map.length是2的n次方了,后面扩容的机制会证明它总是保持着2的n次方。

3.HashMap扩容机制是什么,什么时候扩,每次扩多少?

当超过临界值的时候开始扩充,扩容因子是0.75,当前长度达到总长度*0.75时候,就开始去扩容,每次扩容2倍

4.加载因子为什么是 0.75?

那加载因子为什么是 0.75 而不是 0.5 或者 1.0 呢?
首先如果加载因子比较大,那么扩容发生的频率就比较低,浪费的空间比较小,不过发生hash冲突的几率就比较大,比如加载因子是1的时候,如果hashmap长度为128,那么可能hashmap的实际存储元素数量在64至128之间的时间段比较多,而这个时间段发生hash冲突就比较大,造成数组中其中一条链表较长,就会影响性能。

而当加载因子值比较小的时候,扩容的频率就会变高,因此会占用更多的空间,但是元素的存储就比较稀疏,发生哈希冲突的可能性就比较小,因此操作性能会比较高,比如设置成0.5,同样128长度的hashmap,当数量达到65的时候就会触发hashmap的扩容,扩容后长度为256,256里面只存储了65个似乎有点浪费了。

所以综合了以上情况就取了一个 0.5 到 1.0 的平均数 0.75 作为加载因子

5.那么如何减少哈希冲突呢?

那么需要key对应的存储位置index尽可能的不同。

首先调用hash函数,将key的hashCode值的低16位于高16位进行异或运算,充分的使用hashCode的32个二进制数据进行运算(int是4个字节),得到变量hash。

然后执行位运算hash&(table.length-1),由于数组长度是16,那么table.length-1是15,二进制表示:1111。我们思考这样的一个问题,当数组是16时,hash变量与的是1111,最后会得到hash变量最低4位的值,其范围是0~15。当数组是15时,hash变量与的是1110,那么不管hash变量的最低1位是0或1,得到的值都是0。也就是说,1010,1011与上1110都是1010,两个不同的hash变量有得到同一个存储位置index的可能,这样会更大概率出现哈希冲突。因此,HashMap在设计数组的初始长度为16,数组的扩容也是乘以2。

小结:hash函数利用key的hashCode的高16位和低16位的异或运算,减少了哈希冲突。设计数组长度是16,在执行hash&(table.length-1)运算时,减少了哈希冲突。减少了哈希冲突,充分利用数组空间,HashMap的查询,插入和删除操作会更高效。

https://blog.youkuaiyun.com/zxt0601/article/details/77413921
https://blog.youkuaiyun.com/pihailailou/article/details/82053420

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值