zoukankan      html  css  js  c++  java
  • Java--HashMap的小细节

    通过Hash表实现的一个Map结构,下面通过它的三个主要方法介绍一些技术细节。

    get

    get比较简单,就是通过 key 返回对应的 value。

    那么如何获取key所在下标呢?

    • 首先计算 key 的 hashcode;
    • 将 hashcode 右移16位与自己异或得到 h;
    • h & (length - 1),length是当前 hashtable 的长度,就得到了 key 在 hash 表中的对应的下标

    下面详细说下细节:

    • h & (length - 1)是什么意思?

      如果length为2的幂次,&(length-1) 和 %length 得到的结果是一样的。而位运算效率更高,因此这也是选择表长度为2的幂次的好处之一。

    • 为什么右移16位异或?

      这样操作之后,低16位叠加上了高16位的影响。

      通常来说 hash 表比较小(小于2^16),如果直接拿 key 的 hashcode 取余求下标,那么高16位将不起作用,这样的话如果两个 key 的 hashcode 高位不同,但低位碰巧相同,就会散列到一个桶内。这样做就是避免高位不参与散列作用,减少散列冲突。

    put

    这个也比较简单。通过 key 计算出存储的下标,如果没有元素直接存进去即可,如果有则对比下key是否相同,相同则更新value。如果是链表或者树,遍历或搜索树即可。

    resize

    当表中元素达到一定阈值(75%的表长度)时,为了避免频繁hash冲突,将表扩容(扩大至两倍)。

    • 细节问题在于如何将旧表元素移到新表中去?

      上面说到,计算存储位置时是使用 h&(table.length-1) 来计算的。当我们移到新表的时候,在同样的通过这个方法计算一下下标。

      旧表length-1=15		    1	1   1	1
      key 计算出来的h		a   b	c   d	e
      新表length-1=31		1   1	1   1	1
      

      可以看到第5位a新参与了运算。如果这位为0,那么和旧表计算得到的结果是一样的,这个元素迁移到新表中下标还是不变;如果是1,那么就恰好会多比原来的值大一个oldtable.length,即产生了一个很好的偏移。因为a是由hash值计算得到的,具有很好的随机性,这样每个键值对要么在左边这一半,要么在右边那一半,拆分均匀。仅仅是利用了hash的随机性,没有增加任何其他的操作,实现非常的优美。

    • 对于链表来说如何移动?

      链表也是会根据每个节点的 hashcode 计算,然后就可以拆分成两个链表,一个偏移,一个不偏移。树也是一样的,树的节点在内部其实是串成一条链表的,按链表进行处理,再根据节点数量看是否要转换成树。

  • 相关阅读:
    GC 的认识
    SSRF 攻击技术
    文件包含漏洞
    文件的上传和下载
    XSS
    SQL注入工具 sqlmap
    自动化测试框架
    mac配置环境变量
    pycharm与git想集成 上传下载代码
    测试人员需要掌握的linux基本操作
  • 原文地址:https://www.cnblogs.com/cpcpp/p/15213616.html
Copyright © 2011-2022 走看看