了解HashMap
简述HashMap
HashMap是java里面以Key-value存储的一种集合对象,它底层使用的是数组+链表+红黑树的数据结构,它允许key和value为null,是一种无序并且线程不安全的集合对象
面试题
什么是哈希碰撞
在进行Hash算法时,有可能两个不同的原始值在经过哈希运算后得到同样的结果,这样就是哈希碰撞。
HashMap的默认初始容量为什么一定要是2的幂以及扩容也要为2的幂?
当进行HashMap进行put(key,value)时,假设与HashMap的容量为n,首先对元素的key进行hash运算获取哈希值,将得出来的值与n-1进行与运算–> hash & (n - 1)
之后的出来的值就为哈希桶的下标。
n不为2的幂次方时
假设n为17,n-1的二进制为10000,与hash值运算结果如下:
当n不为2的幂时不同的hash值进行与运算结果可能会出现相同的值,会造成hash碰撞。
n为2的幂次方时
假设n为16,则n-1的二进制为01111,与hash值运算结果如下:
只有n为2的幂时,不同的hash值,和(n-1)进行位运算后,能够得出不同的索引值,使得添加的元素能够均匀分布在集合中不同的位置上,避免hash碰撞。
思考,可以不用与运算获取哈希桶下标吗?
可以使用(hash值 % n)获取下标值
HashMap容量为n,则哈希桶的下标为0~n-1,。
这样的话就没有了容量必须我2的幂这个限制,但是有以下问题:
- 当hash值为负数时,要先将其变为正数(操作是负数+n)
- 速度较慢,取余运算速度较低于与运算
总结
HashMap计算添加元素的位置时,使用的位运算,这是特别高效的运算;另外,HashMap的初始容量16,是2的n次幂,扩容也是2倍的形式进行扩容,这样目的就是可以使添加的元素均匀分布在HashMap中的数组上,减少hash碰撞,避免形成链表的结构,使得查询效率降低!