Java HashMap 的中 key 的哈希值是如何计算的,为何这么计算?

简介: Java HashMap 的中 key 的哈希值是如何计算的,为何这么计算?

首先,我们知道 HashMap 的底层实现是开放地址法 + 链地址法的方式来实现。


微信图片_20220625124921.jpg


即数组 + 链表的实现方式,通过计算哈希值,找到数组对应的位置,如果已存在元素,就加到这个位置的链表上。在 Java 8 之后,链表过长还会转化为红黑树。

这个数组并不是一开始就很大,而是随着 HashMap 里面的值变多,达到 LoadFactor 的界限之后,就会扩容。刚开始的数组很小,默认只有 16。

这个数组大小一定是 2 的 n 次方,因为找到数组对应的位置需要通过取余计算,取余计算是一个很耗费性能的计算,而对 2 的 n 次方取余就是对 2 的 n 次方减一取与运算。所以保持数组大小为 2 的 n 次方,这样就可以保证计算位置高效。

那么这个哈希值究竟是怎么计算的呢?假设就是用 Key 的哈希值直接计算。假设有如下两个 key,哈希值分别是:

key1:

0000 0000 0010 1111 1001 0000 0110 1101

key2:

0000 0000 0010 0000 1001 0000 0110 1101

如果直接使用数组默认大小,取余之后 key1 与 key2 就会到数组同一个下标。其实 key1 和 key2 的高位是不一样的。

由于数组是从小到达扩容的,为了优化高位被忽略这个问题,HashMap 源码中对于计算哈希值做了优化,采用高位16位组成的数字与源哈希值取异或而生成的哈希值作为用来计算 HashMap 的数组位置的哈希值

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

为什么要用异或?首先,对于一个数字,转换成二进制之后,其中为的 1 的位置代表这个数字的特性.对于异或运算,如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。0与0异或是0,0与1异或是1,这样相当于让高位的特性在低位得以体现,所以采用这种算法,减少碰撞。

相关文章
|
1月前
|
Java
【Java】如果一个集合中类型是String如何使用拉姆达表达式 进行Bigdecimal类型计算?
【Java】如果一个集合中类型是String如何使用拉姆达表达式 进行Bigdecimal类型计算?
25 0
|
1月前
|
存储 Java
Java:编写程序,计算两个数的和、差、积、商和余数。docx
Java:编写程序,计算两个数的和、差、积、商和余数。docx
|
1月前
|
算法 Java
算法:Java计算二叉树从根节点到叶子结点的最大路径和
算法:Java计算二叉树从根节点到叶子结点的最大路径和
|
1月前
|
存储 Java
Java 编程实例:相加数字、计算单词数、字符串反转、元素求和、矩形面积及奇偶判断
Java中相加两个数字可通过简单赋值实现,如`int sum = x + y;`。若要用户输入数字相加,可使用`Scanner`类读取。计算单词数,可使用`split()`方法或`StringTokenizer`类。反转字符串,可用`for`循环或`StringBuilder`的`reverse()`方法。计算数组元素总和,可遍历数组累加。矩形面积通过长度乘以宽度得出。判断奇偶性,利用模2运算或位运算检查最低位。更多内容,可关注微信公众号`Let us Coding`。
49 0
|
14天前
|
Java 存储
键值之道:深入学习Java中强大的HashMap(二)
键值之道:深入学习Java中强大的HashMap
20 0
键值之道:深入学习Java中强大的HashMap(二)
|
1月前
|
Java
Java计算每个月的天数
Java计算每个月的天数
|
1月前
|
机器学习/深度学习 算法 Java
Java计算阶乘递归函数的实现
Java计算阶乘递归函数的实现
|
1月前
|
Java
Java:计算两个数的最大公约数和最小公倍数
Java:计算两个数的最大公约数和最小公倍数
|
1月前
|
存储 安全 Java
Java HashMap 和 HashSet 的高效使用技巧
HashMap 是一种哈希表,它存储键值对。键用于查找值,就像数组中的索引一样。HashMap 的优势在于它可以使用任何类型作为键,并且查找速度很快。
64 1
|
1月前
|
Java
Java代码计算两数和差积商余
Java代码计算两数和差积商余
36 0