为何同一类的不同对象调用super.hashCode()返回不同结果?
问题分析与解答
1. 为什么super.hashCode()对el1和el2返回不同结果?
你调用的super.hashCode()实际是调用了父类Object的hashCode()方法。在Java中,Object类的hashCode()默认实现返回的是与对象实例内存地址绑定的唯一值(不同JVM实现细节可能有差异,但核心逻辑是每个独立的对象实例对应不同的hashCode值)。
el1和el2是两个完全独立的DebugTo对象实例,哪怕它们的foo字段值相同,本质上是堆内存中的两个不同对象,所以它们的Object.hashCode()返回值必然不同,和是否属于同一类没有关系。
2. 为什么此处使用super.hashCode()是错误的?
Java语言规范对equals()和hashCode()有强制约定:
如果两个对象通过
equals()方法判断为相等,那么它们的hashCode()必须返回相同的值。
你的equals()方法是基于foo字段的相等性来判断两个DebugTo实例是否相等,但hashCode()方法却将super.hashCode()(对象实例的唯一标识)和foo一起参与哈希计算。这就导致两个foo相同、equals()判断为相等的实例,因为super.hashCode()不同,最终计算出的hashCode也完全不同,直接违反了上述约定。
而HashSet这类集合的工作逻辑是:先通过hashCode()定位元素所在的桶,再在桶内用equals()判断是否存在目标元素。如果两个相等对象的hashCode不同,HashSet会把它们放到不同的桶里,自然不会认为el2已经存在于集合中。
正确的hashCode()实现
应该只基于equals()方法中用到的字段来生成哈希值,也就是只使用foo字段:
@Override public int hashCode() { return Objects.hash(foo); }
这样就能保证所有equals()相等的实例,hashCode()也完全相同,符合Java的规范要求。
内容的提问来源于stack exchange,提问作者peer

