HashMap中我们最常用个方法为put方法
put流程:
1、计算出键的哈希值hashCode
2、根据哈希值计算出索引值hash找到哈希桶的位置
3、若哈希桶放置元素为空则直接插入
4、若哈希桶中有元素(哈希碰撞)则比较内容也就是key值是否相等
1)相等,直接覆盖原先的键值对
2)不相等,若哈希桶中的元素以红黑树的数据结构存储的话则插入红黑树中
否则插入链表后面(注意:链表长度大于8要扩容如果哈希数组的长度大于64则链表大于8的要转换为红黑树)
深入put源码
1、put方法
2、hash方法
要注意:h变量的加入是为了减少哈希碰撞
如果我们直接使用key.hashCode()返回哈希值的话,在进行哈希位运算时(key&(capacity-1))时高位如果变动大的话,对哈希索引值hash的的计算结果的影响是较小的,故而产生哈希碰撞的概率就要大一点。
如下示例
注意红色标注为hashCode二进制码的高位变化
1、
1)假设key=4经过hashCode运算后的到的结果为h(哈希值是比较大的)
1111 1111 1111 1111 0000 1111 0000 1010 h
0000 0000 0000 0000 1111 1111 1111 1111 h>>>16(无符号右移16位) 异或运算
————————————————————————————————————
1111 1111 1111 1111 1111 0000 1111 0101
0000 0000 0000 0000 0000 0000 0000 1111 length-1 进行位运算
————————————
0000 0000 0000 0000 0000 0000 0000 0101 hash=5
2)
1111 1010 1010 1001 0000 1111 0000 1010 h
0000 0000 0000 0000 1111 1010 1010 1001 h>>>16(无符号右移16位) 异或运算
————————————————————————————————————
1111 1010 1010 1111 1111 0101 1010 1000
0000 0000 0000 0000 0000 0000 0000 1111 length-1 进行位运算
————————————————————————————————————
0000 0000 0000 0000 0000 0000 0000 1000 hash=8
2、如果不经过上述处理直接将hashCode计算得出的哈希值进行位运算的话会出现如下结果
1)、假设key=4经过hashCode运算后的到的结果为h(哈希值是比较大的)
1111 1111 1111 1111 0000 1111 0000 1010 h
0000 0000 0000 0000 0000 0000 0000 1111 length-1 进行位运算
————————————————————————————————————
0000 0000 0000 0000 0000 0000 0000 0101 hash=5
2)1111 1010 1010 1001 0000 1111 0000 1010 h
0000 0000 0000 0000 0000 0000 0000 1111 length-1(进行位运算)
————————————————————————————————————
0000 0000 0000 0000 0000 0000 0000 1010 hash=5
上面两个示例的hashCode是一一对应的,但经过哈希值经过无符号右移16位和异或运算与哈希值直接进行位运算得出索引值产生的结果是不一样的,明显未经过处理的哈希值更容易发生哈希碰撞
这就是我们引入变量h后经过一些运算后重新赋值给h进行位运算的原因。