核心是让 hashCode 输出更均匀、计算更轻量、结果可复用;Java HashMap虽有扰动函数,但Key类hashCode若低效或分布差则影响整体性能;宜用31等奇素数乘数配合位运算优化。
核心是让 hashcode 输出更均匀、计算更轻量、结果可复用。java 的 hashmap 本身有扰动函数,但若 key 类的 hashcode 实现低效或分布差,再好的底层也救不了。
用奇素数系数 + 位运算组合计算
避免简单拼接或取模。推荐使用 31 作为乘数(JVM 对 i * 31 会优化为 i ),逐字段参与运算:
- 基础模板:
result = 31 * result + (field == null ? 0 : field.hashCode()); - 字符串字段不用
String.hashCode()再遍历——它本身已高效;但若字段是长文本或 JSON 字符串,考虑只取前 N 位哈希或摘要(如 CRC32) - 数值字段直接参与,布尔用
field ? 1 : 0,枚举用ordinal()或自定义稳定码
缓存 hashCode 值,杜绝重复计算
只要 Key 是不可变的(必须!),就应在构造时算一次并存为 final int hashCode:
- 声明:
private final int hashCode; - 构造器中赋值:
this.hashCode = 31 * Objects.hash(id, type) + status; -
hashCode()方法直接返回该字段,不加锁、不判空、不重算 - 实测显示:百万级 put 操作中,避免每次调用字符串全量遍历,耗时可从 400ms 降至 35ms
精简 equals 比较范围,降低冲突后开销
哈希冲突发生时,HashMap 会遍历桶内节点调用 equals()。若 equals 过重,性能雪上加霜:
- 只比对真正用于区分对象的字段,比如业务主键
id或tenantId + bizCode组合 - 跳过大字段(如
content、remark)、非标识字段(如createTime、version) - 先做快速筛选:先比引用(
this == obj),再比 class,再比核心字段
配合容量预设与负载因子微调
再好的 hash 码,撞上频繁扩容也会放大抖动:
- 初始化 HashMap 时,按预估元素数 ÷ 0.75 向上取整到 2 的幂(如预估 12000 个 key,初始容量设为 16384)
- 若业务 key 分布明确偏斜(如 tenantId 集中在几个值),可略调高 loadFactor 到 0.85,减少扩容次数(需权衡空间)
- 禁止用可变对象(如 ArrayList、Date)作 key;若必须含时间,转为秒级时间戳 long

















