【java基础】HashMap和HashTable

结构

hashTable底层是数组+ 链表
hashMap底层是数组+链表+红黑树

hashMap

数组中的每个元素可视为一个桶,桶里面放的是链表,当桶的个数> 64单链的长度>8,那么链表被替换为红黑树结构,同时使用尾插法。当数据长度<6时候红黑树又转化为单链。

put存取原理:

(1)计算key的hash值,然后进行二次hash,根据二次hash结果找到对应的索引位置
(2)如果这个位置有值,先进性equals比较,若结果为true则取代该元素,若结果为false,就使用高低位平移法将节点插入链表(JDK8以前使用头插法,JDK8之后就用尾插法。但是头插法在并发扩容时可能会造成环形链表或数据丢失,而高低位平移发会发生数据覆盖的情况)

hash冲突

首先需要了解下散列映射,h=f(x),x为键值,h为hash值,f为散列函数,hash冲突是因为x的是无限的,而h的存储范围是有限的,导致x1≠x2,但是f(x1)=f(x2),这就是hash冲突。(理论上不同的哈希值散列映射后的哈希值不相同)

解决hash冲突

1.开发寻址法(线性探测法)
从发生冲突的位置依次往后探测,将空的hash桶放入重复的值
2.链地址法
将重复的hash值放入同一个hash桶里,该hash桶使用单链表存储冲突的元素,各链表的表头结点存放在hash表中。

hashMap<key,value>()
key可以为null,value也可为null;但是只能有一个键值为null,在hashMap源码中当key=null,value=0。
hashTable<key,value>()
key和value都不能为null

在计算hash值的时候(h = key.hashCode()) ^ (h >>> 16),为什么要使用 ‘>>> 16’ 这样的位运算符?
^是逻辑运算异或操作(相同得0,不同得1)
在不参与异或和右移位运算符时候

hash = key.hashCode()    01101010 11101111 11100010 11000100
              (n - 1)    00000000 00000000 00000000 00001111
------------------------------------------------------------
     (n - 1) & hash =    00000000 00000000 00000000 00000100

可以看出,计算后得的值低位一样,只是高位不同而已,这样hash碰撞中很容易相同的键值映射到同一个hash桶里面,而对hash值进行为运算符可以将利用低位部分,而将高位的低位的进行混合就能增加hash值的随机性,使得hash桶的映射更加均匀,提高hash表的性能。

参考文献:
hashMap详解
hashTable详解
HashMap 要用 h^(h >>>16) 计算hash值?槽位数必须是 2^n?

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值