蔚来一面:HashMap 的 hash 方法原理是什么?看完这篇还不懂HashMap的hash原理,那我要哭了~

本文详细解析了HashMap的hash方法,通过JDK 8的源码分析了哈希值如何经过优化以避免碰撞,包括右移和异或运算的作用,以及为何使用&运算代替%运算,以确保数据在HashMap中的均匀分布。

Warning:这是《Java 程序员进阶之路》专栏的第 55 篇。那天,小二去蔚来面试,面试官老王一上来就问他:HashMap 的 hash 方法的原理是什么?当时就把裸面的小二给蚌埠住了。

回来后小二找到了我,于是我就写下了这篇文章丢给他,并严厉地告诉他:再搞不懂就别来找我。听到这句话,心头一阵酸,小二绷不住差点要哭 😭。

PS:本文 GitHub 上已同步,有 GitHub 账号的小伙伴,记得看完后给二哥安排一波 star 呀!冲一波 GitHub 的 trending 榜单,求求各位了。

GitHub 地址:https://github.com/itwanger/toBeBetterJavaer


来看一下 hash 方法的源码(JDK 8 中的 HashMap):

static final int hash(Object key)<
### Java HashMap 实现原理详解 HashMapJava 中非常常用的集合类之一,它实现了 Map 接口,用于存储键值对(key-value)。其底层数据结构基于哈希表实现,能够提供高效的插入、删除和查找操作。以下是关于 HashMap 的实现原理的详细分析。 #### 1. 数据结构 HashMap 的核心数据结构是 **Node 数组** 和 **链表/红黑树** 的组合[^1]。 - **Node 数组**:HashMap 内部维护了一个 `Node<K,V>[] table` 数组,数组的每个位置称为一个桶(bucket)。 - **链表/红黑树**:当同一个桶中存储的元素数量超过一定阈值(默认为 8)时,链表会转换为红黑树以提高查找效率[^3]。 #### 2. 哈希冲突处理 由于哈希函数可能会导致不同的键映射到相同的桶中,这种现象称为 **哈希冲突**。HashMap 通过以下方式解决哈希冲突: - **链地址法**:当发生冲突时,将冲突的元素以链表的形式存储在同一个桶中。 - **红黑树优化**:当链表长度超过阈值(默认为 8),链表会转化为红黑树,从而将时间复杂度从 O(n) 降低到 O(log n)[^4]。 #### 3. 哈希函数 HashMap 使用键对象的 `hashCode()` 方法计算哈希值,并通过位运算和取模操作确定元素在数组中的索引位置[^4]。具体公式如下: ```java int index = (hash & (table.length - 1)); ``` 其中 `hash` 是通过对键的 `hashCode()` 进行扰动计算得到的,目的是减少哈希冲突的概率。 #### 4. 扩容机制 当 HashMap 中的元素数量超过负载因子(load factor,默认为 0.75)与数组容量的乘积时,HashMap 会进行扩容操作。扩容的具体过程包括: 1. 创建一个新的数组,其容量为原数组的两倍。 2. 将原数组中的所有元素重新计算哈希值并放入新数组中(即重新散列)。 扩容操作的时间复杂度为 O(n),因此频繁的扩容会影响性能。为了减少扩容次数,可以在创建 HashMap 时指定初始容量[^2]。 #### 5. 主要方法实现 以下是 HashMap 中几个关键方法的实现原理: - **put(K key, V value)**:根据键的哈希值计算索引位置,如果该位置为空则直接插入;否则检查是否存在相同键,若存在则替换旧值,否则将新元素添加到链表或红黑树中[^3]。 - **get(K key)**:根据键的哈希值定位到对应的桶,然后在链表或红黑树中查找匹配的键并返回对应的值[^1]。 - **remove(K key)**:根据键的哈希值定位到对应的桶,然后在链表或红黑树中移除匹配的键值对。 #### 6. 遍历机制 HashMap 提供了多种遍历方式,最常见的是通过迭代器(Iterator)进行遍历。例如,可以使用增强型 for 循环遍历键集(`keySet()`)、值集(`values()`)或键值对集(`entrySet()`)[^3]。 ### 示例代码 以下是一个简单的 HashMap 使用示例: ```java import java.util.HashMap; public class HashMapExample { public static void main(String[] args) { // 创建 HashMap 对象 HashMap<Integer, String> map = new HashMap<>(); // 插入键值对 map.put(1, "Google"); map.put(2, "Runoob"); map.put(3, "Taobao"); // 获取值 System.out.println("Key 2: " + map.get(2)); // 输出 Runoob // 遍历键值对 for (Integer key : map.keySet()) { System.out.println("Key: " + key + ", Value: " + map.get(key)); } } } ```
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沉默王二

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值