为何Java的hashCode在同应用多次执行时无需保持一致?
为什么Java的hashCode不要求同一应用多次执行时保持一致
首先我们先明确官方规范的定义,Object类的JavaDoc明确给出说明:
该整数值不需要在同一个应用的多次执行过程中保持一致
对应原文:This integer need not remain consistent from one execution of an application to another execution of the same application.
这个设计背后主要有三个核心原因:
- 给JVM实现留出最大的性能优化空间
哈希值的计算逻辑本身没有强制统一的标准,不同JVM厂商、不同版本可以根据自身运行架构选择效率最高的实现方案。比如早期版本的默认hashCode直接基于对象的内存地址生成,而现代操作系统普遍启用ASLR(地址空间布局随机化)安全机制,同一应用每次启动时对象的内存起始地址都会变化,强制要求哈希值跨执行一致反而需要额外增加持久化存储哈希值的逻辑,既会增加对象头的内存开销,也会拖慢哈希计算的速度。 - 降低哈希碰撞攻击的风险
如果要求哈希值跨执行固定,攻击者可以很容易提前批量计算出哈希值冲突的键,向HashMap、HashSet等基于哈希的容器中插入这些冲突数据,会直接导致哈希表退化为链表,读写时间复杂度从O(1)骤降到O(n),触发拒绝服务攻击。JDK 7之后引入的随机哈希种子机制,就是利用了跨执行哈希值不固定的特性,每次应用启动生成不同的哈希种子,大幅提高攻击者构造冲突键的成本,提升了哈希容器的安全性。 - 不违背
hashCode的核心契约
Java对hashCode的强制约束仅针对单次应用运行的生命周期内,一共三条:- 同一对象在自身参与
equals计算的属性没有发生变更的前提下,多次调用hashCode()必须返回相同的整数值 - 若两个对象通过
equals()方法判断为相等,则两者的hashCode返回值必须相等 - 若两个对象通过
equals()方法判断为不相等,不要求两者的hashCode返回值一定不同,但差异化的哈希值可以提升哈希容器的运行效率
跨执行保持一致完全不在核心约束范围内,合理的业务代码本身也不应该依赖hashCode的跨执行一致性,放宽这个约束不会影响任何符合规范的代码运行。
- 同一对象在自身参与
内容的提问来源于stack exchange,提问作者Mohammad Yasin
相关产品推荐
相关产品推荐

