HashMap是怎样实现快速查找的

业界流传着这样一句话"时间换空间,空间换时间",用这句话来形容HashMap非常的合适,其内部用一个大数组存储所有的value,并根据key直接计算出value应该存储在那个索引,如图:例如(key的hash值为假设)key="a" value="张三"的数据就存在索引index=1处,key="b" value="李四"的数据就存在索引index=3处

key索引的计算

key的索引计算很简单,以"a"为例,就是字符串"a"的hash值,故此我们经常使用String 作为 key,因为String 已经正确覆写equals方法.但如果我们放入的key 是一个自己写的类,就必须保证正确覆写equals方法.相同的key 对象(使用equals判断时返回true)必须要计算出相同的索引,否则,相同的key每次取出value就不一定对

通过key计算索引的方式就是调用key对象的hashCode()方法,它返回一个int整数.HashMap正是通过这个方法直接定位key对应的value的索引,继而直接返回value.

 HashMap源码默认原始大小为16,那么问题就来了,我们定义的key计算后的hash值如果是超过了这个界限怎么办?hashCode()返回的int返回高达±21亿,先不考虑负数,HashMap内部使用的数组得有多大

其实这个问题也不低担心无论它的hashCode()有多大,都可以简单地通过:

int index = key.hashCode() & 0xf; //0xf = 15

 如上,我们得知字符串"王哈哈"的hash值为29119947,它跟15与完以后结果变成了11,这对于程序员来说理解起来不难,因为这个与的操作是在二进制的基础上与的

0001 1011 1100 0101 0101 1100 1011  (29119947的二进制)

                                                      1111  (15的二进制)

                                                      1011  (结果,十进制结果为 11)

那么如果超过了初始长度怎么办?

HashMap会在内部自动扩容,每次扩容一倍,即长度为16的数组扩展为长度为32,相应的,需要重新计算hashCode() 索引位置.那么如上例子的计算方式就会变为

0001 1011 1100 0101 0101 1100 1011  (29119947的二进制)

                                             0001 1111  (31的二进制)

                                                      1011  (结果,十进制结果为 11)注意这里只是恰巧两个结果一样,并不是所有的结果都一样

由于扩容会导致重新分布已有的key-value,所以,频繁扩容对HashMap的性能影响很大.如果我们确定要使用一个10000个key-value的HashMap,更好的方式是创建HashMap时就指定容量: Map<String,Integer> map = new HashMap<>(10000); 

虽然指定容量是10000,但是HashMap内部的数组长度总是 (2^n),因此,实际数组长度被初始化为比10000大的16384((2^14))

装了阿里巴巴代码公约插件的效果版应该都注意到过这个提示

 此时看似完美,但还有一个问题,那就是有一些key计算后的hash值是一样的 我们就假设"a" 和"b" 这两个key 最终计算出的索引都是3,那么,在HashMap的数组中,实际存储的不是一个Person实例,而是一个List,它包含 两个Entry,一个是"a"的映射,一个是"b"的映射:

HashMap内部通过"a"找到的实际上是List<Entry<String,Person>>,它还需要遍历这个list,并找到一个Entry,它的key字段是"a",才能返回对应的Value

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值