zoukankan      html  css  js  c++  java
  • 关于hashMap中 计算hashCode的逻辑推理(二)

    hashMap中,为了使元素在数组中尽量均匀的分布,所以使用取模的算法来决定元素的位置.如下:

    1 //方法一:
    2 static final int hash(Object key){//jdk1.8
    3   int h;
    4   return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    5 }
    6 //方法二:
    7 static int indexFor(int h,int length){//低版本的源码
    8   return h & (length - 1);//第三步,取模运算
    9 }

    方法一是我当前使用jdk版本的源码,

    方法二是在网上查到的低版本的源码,

    首先确认:当length总是2的n次方时,  h & (length - 1)   等价于   hash对length取模      ,但是&比%具有更高的效率;(下文有对该方法的说明).

    其次,方法一和方法二的原理是一样的,

    在JDK1.8的实现中,优化了高位运算的算法,通过hashCode()的高16位异或低16位实现的:(h = k.hashCode()) ^ (h >>> 16),

    主要是从速度、功效、质量来考虑的,这么做可以在数组table的length比较小的时候,也能保证考虑到高低Bit都参与到Hash的计算中,同时不会有太大的开销。

    -----------------------------------

    另开头:

    为什么数组大小为2的幂时hashmap访问性能最高?

    我在网上查了一些博文,好多都”举例说明“,来以事实说话,

    其实我感觉这有取巧的嫌疑,

    以下为我个人理解(错误的理解,文章结尾处已写明)

    为什么取length(奇数)-1?  而不是 length(偶数)-1?

    在进行&(逻辑与)运算时(例:a & b),只有当 a =true and b =true 时,结果才是 1,否则都是0;

    所以,当 hash & 偶数  时,  二进制结果 就总会是偶数,这就导致 数组的偶数位被浪费,数组的奇数位的冲突概率 增高.

    基于以上,所以  存储位置index = h & (length - 1);   中length取偶数 使得  hashMap具有更高的性能.

    至于为什么选择 为2的幂?    接触尚短,我暂时还没想到,待后续.

    -----------------------------------------------------------------------------------------

    通过研读前辈们的博文,以下 为 为什么使用 2的幂 作为数组长度:

    当容量一是为2的幂 时,h&(length - 1) == h%length,它俩是等价不等效的.!!!!!!!!

    -------------------------

    推导:

    2^n转换成二进制就是1+n个0,减1之后就是0+n个1, 如16 -> 10000,15 -> 01111,那根据&位运算规则,都为1时,才为1,那0≤运算后的结果≤15,

    假设h <= 15,那么运算后的结果就是h本身,h >15,运算后的结果就是最后三位二进制做&运算后的值,最终,就是%运算后的余数.

    补充:

    通过位运算(不用模运算符%)求余

    前提:a/b的除数 b必须为2的 你次方.也就是说b必须是

    2的一次方 1

    2的二次方 4

    2的三次方 8

    ......

    ......

    只有是这样的一种情况,这种方法才是正确的.

    如下两种方法:

    方法一:a%b = a&( b -1);

    例:

    a=9 , b= 8.   小括号内的值为b-1 = 8-1 =7. 9 的二进制表现:1001,7的二进制表现:0111, a%b = a&(b-1) = 9%8 = 9&(8-1) 的结果值:0001 = 1.也就是说,余数为1.结果是正确的.

    方法二:a%b = a-((a>>log2[b])<<log2[b]);

    例:

    初始值还是 a= 9,b = 8. a-((a>>3)<<3) 先右移3位,再左移三维,然后a减去移位后的值.

    在hashMap中使用的方法一.

    因此,容量(数组长度)必须为2的幂方.

    上文中我自己的想法也是不对的. 长度取偶数  那只是取2的幂方的  结果属性.并不是原因之一.上文就不删改了, 留下个记号完整学习过程.

  • 相关阅读:
    转:spring-session
    转:SpringBoot项目如何进行打包部署
    事务的隔离级别
    获取打卡记录接口返回数据情况说明
    批注@SuppressWarnings 的作用
    mybatis-generator eclipse插件 使用方法
    几种常见数据库的driverClassName和url
    ssm 配置多个数据源
    常用正则表达式
    tomcat 配置成服务
  • 原文地址:https://www.cnblogs.com/zqsky/p/6777654.html
Copyright © 2011-2022 走看看