目录
(1)为什么^可以增加哈希值的随机性,从而减少哈希冲突的可能性
(2)为什么要h >>> 16?为什么是16位,左移操作可以吗,不移动可以吗?
1.3解析getNode(int hash, Object key)
3.1 默认初始容量default_initial_capacity
3.4 退化为链表阈值untreeify_threshold
3.5 桶数组的最小容量min_treeify_capacity
我主要从hashMap的源码层面,解析get函数、put函数这2个方法的核心逻辑,最后再说明下HashMap的关键属性的含义。
1 解析get(Object key) 方法
1.1 源码展示
public V get(Object key) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
后面重点剖析hash函数和getNode函数。
1.2 解析hash(key) 方法
hash(Object key)用来确定键值对在内部数组中的存储位置的关键算法,源码如下:
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
1.2.1 解析(key == null) ? 0
这部分是一个三元运算符,用于检查传入的键(key)是否为null。如果key为null,则返回0。这是因为在Java中,任何对象与null比较都会返回false,而HashMap需要一个非负的哈希值来确定存储位置。如果key不为null,则执行后面的代码。
1.2.2 解析(h = key.hashCode())
如果key不为null,则调用key的hashCode()方法来获取其哈希值,并将其赋值给变量h。hashCode()方法在Object类中定义,并被HashMap的键对象所继承。这个方法的目的是返回一个代表对象的哈希码值,通常是通过对象内部的一些数据计算得到的。
1.2.3 解析^ (h >>> 16)
^是按位异或运算符,它对两个二进制数进行按位异或操作。在这个上下文中,h >>> 16
是将变量h
的32位哈希值向右移动16位,这相当于对哈希值进行了一次高位的丢弃,保留了低16位的值。然后,这个结果与原始的哈希值h
进行按位异或操作。
按位异或操作的特点是,如果两个比特位相同,则结果为0
;如果两个比特位不同,则结果为1
。这种操作可以增加哈希值的随机性,从而减少哈希冲突的可能性。
(1)为什么^可以增加哈希值的随机性,从而减少哈希冲突的可能性
-
非线性变换:按位异或是一种非线性的位运算操作。当两个操作数的对应位不同的时候,结果为1;当对应位相同时,结果为0。这种非线性的特性使得异或操作能够将输入的位模式转换成一个看似随机的输出模式。这种转换有助于将输入数据中的局部相似性打散,从而使得输出的哈希值在位上看起来更加随机和分散。
-
位分布均匀:异或操作能够使输出的每一位都依赖于输入的多位,这样可以使得输出的每一位都有较高的熵(即不确定性)。当输入的哈希值经过异或操作后,每一位的值都与输入的多位有关联,这样可以使得每一位的输出结果更加均匀,减少了某些位可能聚集特定值的可能性。
-
减少连续相同位的可能性:在哈希值中,连续的相同位(如连续的0或1)可能导致哈希表中的冲突增加。异或操作通过改变位的值,可以打破这种连续性,从而减少连续相同位的可能性,有助于分散哈希值,减少冲突。
-
混合高位和低位信息:在代码
(h = key.hashCode()) ^ (h >>> 16)
中,h >>> 16
是将哈希值的高16位移到低16位的位置,然后与原始的哈希值进行异或操作。这样做可以将高位的信息与低位的信息混合起来,增加了哈希值的整体随机性,有助于避免某些特定的高位模式导致的冲突。 -
对抗哈希碰撞攻击:在某些情况下,攻击者可能会尝试构造特定的输入数据,使得它们的哈希值相同,从而引发哈希碰撞。通过使用异或操作,可以在一定程度上对抗这种攻击,因为它增加了攻击者预测和控制哈希值输出的难度。
(2)为什么要h >>> 16?为什么是16位,左移操作可以吗,不移动可以吗?
在Java的HashMap中,对哈希值进行右移操作(h >>> 16)而不是左移(h << 16),以及选择移动16位而不是其他位数,都是基于特定的设计考虑和优化策略。
1. 右移 vs 左移:
右移操作(>>>)与左移操作(<<)在位运算中有不同的效果。左移操作将所有位向左移动,右边填充0,这实际上是放大了数值的低位部分,而高位则被丢弃。右移操作则是将所有位向右移动,左边填充符号位(对于有符号整数),这样做保留了数值的高位部分,但丢弃了低位部分。
在HashMap中,右移操作有助于保留原始哈希值的高位信息,同时通过丢弃低位信息来增加哈希值的随机性。这是因为高位通常包含更多的信息,而低位可能包含更多的随机噪声。通过这种方式,可以在一定程度上减少哈希冲突,因为高位信息对于区分不同的键更为重要。
2. 移动16位 vs 移动其他位数:
选择移动16位而不是其他位数是基于性能和效果的平衡。移动16位意味着原始哈希值的高16位和低16位被交换,这样可以更好地混合哈希值的高位和低位信息,增加随机性,从而减少哈希冲突的可能性。
如果选择移动的位数太少,比如8位,那么混合的效果可能不明显,高位和低位的信息可能仍然保持较大的独立性,这可能导致哈希值的分布不够均匀。如果移动的位数太多,比如24位,那么保留的信息就会更少,这可能会导致哈希值的随机性降低&#