HashMap是Java集合框架中基于哈希表实现的Map接口实现类,支持存储键值对结构的数据,允许键和值为null,不保证元素的存储顺序,是日常开发中处理键值映射场景的常用工具。

HashMap存储键值对的基础用法
使用HashMap存储键值对核心是通过put方法添加数据,通过get方法根据键获取对应的值,以下是基础的使用示例:
import java.util.HashMap;
import java.util.Map;
public class HashMapDemo {
public static void main(String[] args) {
// 创建HashMap实例,键为String类型,值为Integer类型
Map<String, Integer> scoreMap = new HashMap<>();
// 存储键值对,键为学生姓名,值为对应分数
scoreMap.put("张三", 85);
scoreMap.put("李四", 92);
scoreMap.put("王五", 78);
// 根据键获取对应的值
Integer zhangScore = scoreMap.get("张三");
System.out.println("张三的分数:" + zhangScore);
// 判断键是否存在
boolean hasLi = scoreMap.containsKey("李四");
System.out.println("是否存在李四的记录:" + hasLi);
// 遍历所有键值对
for (Map.Entry<String, Integer> entry : scoreMap.entrySet()) {
System.out.println("姓名:" + entry.getKey() + ",分数:" + entry.getValue());
}
}
}
上述代码演示了HashMap的创建、添加数据、查询数据、遍历数据的基础操作,除了这些常用方法外,还可以使用remove方法删除指定键的键值对,使用size方法获取存储的键值对数量。
哈希碰撞的产生原理
哈希碰撞指的是不同的键通过哈希函数计算后得到相同的哈希值,进而导致在哈希表中映射到同一个存储位置的现象。HashMap中哈希值计算的逻辑是对键的hashCode方法进行二次扰动后得到的,当两个不同的键计算出的哈希值相同,或者在哈希表中映射到的桶索引相同时,就会产生哈希碰撞。
比如有两个字符串"Aa"和"BB",它们的hashCode值都是2112,经过HashMap的哈希扰动逻辑后得到的哈希值依然相同,当HashMap的表长度足够小时,这两个键就会映射到同一个桶位置,产生哈希碰撞。
HashMap中哈希碰撞的解决方法
JDK 1.8之前的解决方案:拉链法
在JDK 1.8之前,HashMap解决哈希碰撞的核心方式是拉链法,也就是当发生哈希碰撞时,将碰撞的元素以链表的形式存储在同一个桶位置中。查找时先根据哈希值找到对应的桶,再遍历桶中的链表找到目标键。
JDK 1.8及之后的优化方案
JDK 1.8对HashMap的哈希碰撞处理做了优化,当同一个桶中的链表长度大于等于8,并且当前哈希表的长度大于等于64时,会将链表转换为红黑树,这样可以将查找时间复杂度从链表的O(n)降低到红黑树的O(log n),提升哈希碰撞场景下的查询性能。
以下是HashMap中判断是否需要树化的核心逻辑片段:
// 当链表长度达到阈值8时的处理逻辑
if (binCount >= TREEIFY_THRESHOLD - 1) {
// 尝试将链表树化,若表长度不足64会先扩容
treeifyBin(tab, hash);
break;
}
同时HashMap还会通过扩容机制来减少哈希碰撞的概率,当哈希表中存储的键值对数量达到阈值(容量乘以负载因子,默认负载因子为0.75)时,会将哈希表的容量扩大为原来的两倍,重新计算所有键的存储位置,分散原本集中在同一个桶中的元素。
使用HashMap的注意事项
为了减少哈希碰撞的发生,自定义对象作为HashMap的键时,需要正确重写hashCode和equals方法,保证相等的对象一定有相等的哈希值,同时要尽量让hashCode的计算结果分布均匀。另外不要将可变对象作为HashMap的键,否则对象内容修改后哈希值会变化,导致无法正确查询到对应的值。
JavaHashMap键值对哈希碰撞hash_collision修改时间:2026-06-14 13:45:15