• hashMap tableSizeFor 实现原理


    基于jdk1.8

    hashMap实现,要求容量大小是2的整次方,例如:2/4/8/16/32/64/128...,而不能是中间的某个值。这是为什么呢?

    map是数组+链表的数据结构,读写数据都需要首先获取数组中的下标值,获取的方式是通过hashcode取余。取余so easy,我们都会,假定运算后的hashcode=17,容量大小capacity=16,17%16=1,很容易得出元素落在数组的下标[1]内。

    但是还有一种方式可以获取到正确的下标值,17 &(16-1)=1。

    17二进制: 10001

    15二进制: 01111

    17&15:     00001 = 1

    计算机的物理特性,决定位运算才是取余的正确打开方式。但是却有一个限制,被位与的数值有效位必须全部都是1,如15:1111可以,13:1101则不行

    这里位与运算得到的是下标位置,数组容量要在最大下标值的基础上加1,等价于二进制中被位与的数值进位,如15进1位=16:10000,2的4次方。

    如果我们new HashMap<>(13),输入一个非整次方的数值,hashmap会自动调整成最近的整次方,例如这里的13最终会转换成16,实现方法为:java.util.HashMap#tableSizeFor

    怎么实现呢?

    2的整次方的特性是二进制有效位只有一个1,退位后当前1消失,后面bit位全补1,例如16:10000,退位后01111。13的二进制:1101,结构上看只要第二个bit补1(1101->1111),再进位(1111->10000)就可以了。1101->1111->

    我们来分析实现

    首先把方法复制出来,加上一些日志方便分析:

    static final int MAXIMUM_CAPACITY = 1 << 30;
    
    static final int tableSizeFor(int cap) {
        System.out.println(Integer.toBinaryString(cap));
        int n = cap - 1;
        System.out.println(Integer.toBinaryString(n));
        n |= n >>> 1;
        System.out.println(Integer.toBinaryString(n));
        n |= n >>> 2;
        System.out.println(Integer.toBinaryString(n));
        n |= n >>> 4;
        System.out.println(Integer.toBinaryString(n));
        n |= n >>> 8;
        System.out.println(Integer.toBinaryString(n));
        n |= n >>> 16;
        System.out.println(Integer.toBinaryString(n));
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }
    
    public static void main(String[] args) {
        tableSizeFor(MAXIMUM_CAPACITY);
    }
    int n = cap - 1先退位,所以最终实现的结果是n的bit位全补1

    使用的最大容量+1,这样看日志比较清晰。

    1000000000000000000000000000001
    1000000000000000000000000000000
    1100000000000000000000000000000
    1111000000000000000000000000000
    1111111100000000000000000000000
    1111111111111111000000000000000
    1111111111111111111111111111111
    

    看到规律了吗?tableSizeFor首先获取最高位的1,二进制退位规则决定一定能够获取到最高位的1,然后进行不停的bit复制,1生2,2生4等等。int类型只有32位,所以复制到16位终止。

    最后将n进位,即得到2的整次方,不过限定不能大于1>>30;

  • 相关阅读:
    java生成UUID通用唯一识别码 (Universally Unique Identifier)
    使用ToolRunner运行Hadoop程序基本原理分析
    Hadoop入门经典:WordCount
    Hadoop配置文件
    【Nutch2.2.1基础教程之3】Nutch2.2.1配置文件
    8大排序算法图文讲解
    动态字典树_前缀相互查找(HDU_1671)
    DP_基本DP+排序(HDU_1421)
    斯特灵公式
    七种 qsort 排序方法
  • 原文地址:https://www.cnblogs.com/yangmengdx3/p/9249142.html
Copyright © 2020-2023  润新知