Object 的 equals() 默认比较的是对象的内存地址
hashCode() 也是对对象的内存地址进行hash。
所以在涉及到hashcode的容器中(比如HashSet),判断自己是否持有该对象时,会先检查hashCode是否相等,如果hashCode不相等,就会直接认为不相等,并存入容器中,不会再调用equals进行比较。
但是hashCode()会出现哈希冲突,当发现哈希冲突时,便需要equals方法进行判断两者是否相等
如果重写了equals方法,相等的元素内存地址不一定相等。若不重写hashcode,还是可能会发生元素相同问题。所以要重写hashCode()。因此要重写hashCode保证:如果equals判断是相等的,那hashCode值也要相等。
哈希冲突:不同数值却拥有相同哈希值。
在Java中,equals()
方法用于比较对象的内容是否相等,而 hashCode()
方法用于获取对象的哈希码。这两个方法在某些场景下是紧密关联的,尤其是在使用哈希集合(如 HashMap
、HashSet
)时。在这篇博客中,我们将深入探讨为什么在重写 equals()
方法的同时必须重写 hashCode()
方法。
相等对象应该有相等的哈希码
在Java中,如果两个对象通过 equals()
方法判断相等,那么它们的哈希码应该相等。反之亦然,即如果两个对象的哈希码相等,它们不一定通过 equals()
方法判断相等。
为什么要保持这种关系呢?原因在于哈希集合的实现,比如 HashMap
。这些集合通过哈希码来确定对象在内部数据结构中的存储位置。当我们尝试查找某个对象时,先根据哈希码定位到可能的存储位置,然后再通过 equals()
方法来确保找到的是真正相等的对象。
如果两个相等的对象具有不同的哈希码,那么它们将被存储在不同的位置,导致无法正确地通过 equals()
方法找到这些对象。
重写 equals() 的常见场景
1.类表示值: 如果一个类的实例是不可变的,并且表示值(如字符串、数字),那么通常需要重写 equals()
方法。
@Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; MyClass myObject = (MyClass) obj; return Objects.equals(value, myObject.value); }
2. 自定义类: 自定义类需要比较对象的内容时,也需要重写 equals()
方法。
@Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; Person person = (Person) obj; return age == person.age && Objects.equals(name, person.name); }
为什么必须重写 hashCode()
在Java中,hashCode()
方法返回对象的哈希码,它在哈希集合中起着关键的作用。当我们将对象放入哈希集合时,集合通过对象的哈希码来决定对象的存储位置。
如果我们在重写了 equals()
方法的同时不重写 hashCode()
方法,可能导致以下问题:
- 相等对象哈希码不同: 如果两个对象通过
equals()
判断相等,但它们的哈希码不同,这将违反哈希集合的原则,导致无法正确处理相等对象。 - 相同哈希码不等对象: 如果两个对象的哈希码相等,但它们通过
equals()
判断不相等,这可能导致哈希集合中存储重复的对象,破坏集合的正确性。
因此,为了确保哈希集合正常运作,必须同时重写 equals()
和 hashCode()
方法。这可以通过IDE(如Eclipse、IntelliJ IDEA)提供的工具来自动生成。
重写 hashCode() 的实例
@Override public int hashCode() { return Objects.hash(name, age); }
这个例子中,使用 Objects.hash()
方法来组合多个属性的哈希码,以确保生成的哈希码是基于所有相关属性的。这有助于避免相等对象的哈希码不同的问题。
总结
在Java中,equals()
和 hashCode()
方法的正确实现对于正确使用集合类非常重要。通过保持相等对象具有相等的哈希码,我们可以确保哈希集合的正确性,防止发生数据结构中的问题。因此,在重写 equals()
方法时,务必同时重写 hashCode()
方法,以维护良好的编程实践。