浅析Java中HashMap的底层原理

什么是HashMap

HashMap是一个用来存储键值对的数据结构,每一个键值对也叫做Entry,这些键值对(Entry)分散存储在一个数组当中,HashMap的每个元素初始值都为null
对于HashMap我们有两种常用的方法Put和Get, 声明方式: HashMap map=new HashMap()。
HashMap的默认长度是16并且每次自动扩展或者手动扩展时长度必须为2
的幂。具体请看下面关于HashCode的介绍。**

  • Put方法
    对于Put方法,比如调用map.put(“apple”,0),插入一个key为”apple”的value为0的元素,这个时候需要一个index来确定它在HashMap中的索引位置,但是HashMap的长度是有限的,当插入的Entry越来越多时,会发生index冲突的情况,这个时候我们该怎么办呢?其实在HashMap中每一个元素不止是一个Entry对象,也是一个链表的头结点,每一个Entry对象都会有一个next指针指向它的下一个Entry对象,当新来的Entry发生映射冲突时,只需要插入相应的链表即可。

  • Get方法
    我们使用Get方法来根据输入的Key来查找Value会发生什么呢?
    首先我们会将输入的Key来做一次Hash映射来得到相应的index,由于刚才所说的Hash冲突,一个index可能对应多个Entry对象,这个时候就要顺着相应的Entry头结点一个一个向下来找。

  • 和HashTable的区别
    ①HashTable是一个线程安全的Map实现,但是HashMap是不安全的实现,所以HashMap的性能要高于HashTable,但是如果在高并发的情况下,HashTable实现类会更好一点。
    ②HashTable不允许用null值来作为key,value。如果试图把null值来作为元素放入HashTable中会引发NullPointerException异常;但是null可以在HashMap中被支持。

    关于HashCode

    上面提到根据key的值来计算Entry在HashMap中索引位置,这个过程称为一次Hash映射,index=Hash(“element”),那么如何实现一个尽量分布均匀的Hash函数呢,我们利用Key的HashCode来进行某种运算,为了实现高效的Hash算法,HashMap的发明者采用了位运算的方式。
    index=HashCode(Key)&(Length-1) ,举个例子,假定book的HashCode结果为十进制的3029737,对应的二进制为1011100011101011101001,再假定HashMap的长度Length为默认的16,Length-1的值为15,对应的的二进制为1111,1011100011101011101001,1111&1011100011101011101001=1001,十进制是9,所以index=9。可以说Hash算法得到的index完全取决于Key的HashCode的后几位。
    为什么长度必须为2的幂呢,假定HashMap的长度为10,10-1得到的Length长度为9,对应的二进制为1001,1001&1011100011101011101001,计算出来的结果为1001,虽然还是9,但是我们换个HashCode试试,对于1011100011101011101111来说,运算结果为1001,index的值还是9,当HashMap长度不为2的幂的时候,有的index出现的几率更大,而有的index则永远不会出现比如(0111),这显然违背了Hash算法均匀分布的原则,反观长度为2的幂的时候,最后的HashCode的二进制位全为1,index等同于HashCode后几位的值,只要输入的HashCode本身分布均匀,那么Hash算法的结果就是均匀的。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值