• Java源码之HashMap的hash篇


    提到哈希,我们脑袋中立马就会闪过一个方法,就是hashCode(),没错。就是这个!
    我们知道HashMap是通过 数组+链表 的结构进行数据存储的,有数组就会有索引,而HashMap内的数据要存储在哪块索引上,则是基于HashMap内部的hash方法计算出来的。
    我们常用的 get put 也离不开这个 hash 方法。
    我们先从hash方法入手!

    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
    

    首先通过 hashCode() 方法得到 h ,然后在把 h 无符号右移16位,最后通过异或算法得到hash值,我们找个key展开运算一下
    假设有一个key

    String key = "hello world";
    

    那么这个key的hashCode的二进制为
    0110 1010 1110 1111 1110 0010 1100 0100
    然后把这个二进制数据向右无符号移动16位,得到如下
    0000 0000 0000 0000 0110 1010 1110 1111
    最后通过把高16位和低16位做异或运算均匀分布
    0110 1010 1110 1111 1000 1000 0010 1011
    给hash做异或运算主要还是为了降低hash冲突的概率(这个是查阅资料得知的)

    我们说完hash的运算过程后,看一下HashMap里边都是哪里有用到吧

    public V get(Object key) {
        Node<K,V> e;
        return (e = getNode(hash(key), key)) == null ? null : e.value;
    }
    public boolean containsKey(Object key) {
        return getNode(hash(key), key) != null;
    }
    public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }
    

    这三个方法,算是HashMap内最常用的三个方法了,可以看到从应用层传递进来的key全部都经过了hash(key)而比较细心的朋友们还会发现HashMap内数组的索引,是通过 i = (n - 1) & hash 计算得出的

    我们接下来在展开一下索引计算公式
    n是HashMap内的哈希表的长度,默认是16,每次扩容都是一倍一倍的扩容,就是 16 << 1 ,我们拿16来展开运算,而hash用上面的key来继续运算

    i = (16 - 1) & hash

    15的二进制结果是
    0000 0000 0000 0000 0000 0000 0000 1111

    hash的再拿过来用吧~(十进制:1794082859)
    0110 1010 1110 1111 1000 1000 0010 1011

    在通过&运算,可以得到(十进制:11)
    0000 0000 0000 0000 0000 0000 0000 1011

    十进制计算:
    1794082859 & 15 = 11
    1794082859 % 16 = 11

    首先n在HashMap里的设定是永远都是2次幂,因为 2次幂 & hash(key) 等价于 hash(key) % n
    而众所周知,& 比 % 效率要高10倍的。
    但这个公式只有 n 是2次幂的时候才成立,所以才有了2次幂的设定。

    HashMap的索引都是通过这个算法得出来的,所以HashMap查找起来特别快~

    好了,通过这篇文章,大家应该也对HashMap的hash有点概念了。

    一个被程序耽误的画手
  • 相关阅读:
    iOS sandbox
    属性和成员变量
    SDWebImage
    MRC和ARC混编
    MRC转ARC(2)
    MRC转ARC
    CentOS7.x关闭防火墙
    Linux下Tomcat带日志启动命令
    SpringBoot-属性文件properties形式
    SpringBoot-配置Java方式
  • 原文地址:https://www.cnblogs.com/kezhuang/p/13659314.html
Copyright © 2020-2023  润新知