HashMap详解-内部实现原理(2)-哈希函数

引言

HashMap 使用哈希函数将键映射为整数,该整数即为键的哈希值。哈希函数的设计直接影响到 HashMap 的性能。一个良好的哈希函数应该能够尽可能地将键均匀地映射到桶中,减少哈希冲突的概率,所以了解哈希函数其实是挺重要的。

哈希函数在HashMap中的实现流程

  1. 获取键的哈希码:使用键对象的 hashCode() 方法获取其哈希码。hashCode() 方法通常会将对象的内部状态转换为一个整数,作为哈希码的基础。
        public final int hashCode() {
            return Objects.hashCode(key) ^ Objects.hashCode(value);
        }
  1. 扰动(混合)哈希码:使用哈希码对表容量进行扰动,目的是减少哈希冲突的概率。这一步是通过对哈希码进行异或、位移和取模等操作来实现的。
    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
  1. 计算桶索引:根据扰动后的哈希码和表容量计算桶的索引(数组下标)。具体计算公式为 hash & (tab.length - 1),其中 hash 是扰动后的哈希码,tab.length 是表的长度。
        //该代码出现在HashMap源码中的putVal方法
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);

只是说概念可能没什么感觉,下面是一个例子来帮助理解哈希函数的使用

假设有一个 初始容量为16的HashMap。我们要插入一个键为 “sky” 的键值对。

  1. 获取键的哈希码:调用 “sky” 的 hashCode() 方法,假设得到的哈希码为
    00000001110000011000000110100100。

  2. 扰动哈希码:对哈希码进行异或、位移和取模等混合操作。
    扰动方法为:h^(h >>> 16)
    根据我们的示例,进行混合操作后的哈希码为 00000001110000011000000001100101。

  3. 计算桶索引:根据扰动后的哈希码和表容量计算桶的索引。
    计算桶索引的公式为 h & (n - 1)
    进行计算后得到:00000000000000000000000000000101即下标为5
    因此,键 “sky” 将被插入到索引位置为 5 的桶中。

  4. 最终,键值对 (“sky”, value) 将被插入到索引位置为 5 的桶内。

需要注意的是,HashMap 在处理哈希冲突时会使用链表或红黑树来存储键值对。但哈希函数的作用仍然是将键均匀地映射到桶中,减少冲突的概率,从而提高 HashMap 的性能。

你可能感兴趣的:(哈希算法,散列表,算法)