两个对象不相等,HashCode 有可能相等吗?
最近在刷博客的时候看到一个挺有意思的面试题:“两个对象相等,Hashcode 一定相等,那如果两个对象不相等,HashCode 有没有可能相等?”这个问题涉及 Java 的 equals 和 hashCode 方法的工作原理和约定。本文将详细探讨这一问题,并解释其中的逻辑。
equals 和 hashCode 方法的契约
在 Java 中,每个对象都有两个重要的方法:equals 和 hashCode。这两个方法在集合框架(如 HashMap 和 HashSet)中扮演着关键角色。为了确保这些集合正确工作,必须遵守以下契约:
- equals 方法契约:
自反性:对于任何非空引用值 x,x.equals(x) 应返回 true。
对称性:对于任何非空引用值x和y,x.equals(y)应返回true仅当y.equals(x) 返回 true。
传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,则 x.equals(z) 应返回 true。
一致性:对于任何非空引用值 x 和 y,只要在 equals 比较中所用的信息没有被修改,反复调用 x.equals(y) 应一致地返回 true 或 false。
非空性:对于任何非空引用值 x,x.equals(null) 应返回 false。
2. hashCode 方法契约:
一致性:只要在equals比较中所用的信息没有被修改,反复调用hashCode方法时,必须一致地返回同一个整数。
等价对象的相等hashCode:如果两个对象根据equals(Object)方法是相等的,那么调用这两个对象中的每一个的hashCode方法必须产生同样的整数结果。
不等对象的非强制性:如果两个对象根据equals(Object)方法是不相等的,则这两个对象中的每一个的hashCode方法的返回值不要求不同。然而,不相等的对象生成不同的hashCode值有助于提高哈希表的性能。
两个对象不相等,hashCode 有可能相等吗?
根据上述契约,两个对象不相等,它们的hashCode可能相等。这样的情况被称为哈希碰撞。由于hashCode方法返回一个 32 位整数,而对象的数量远远超过 2^32,因此哈希碰撞是不可避免的。
例子
考虑以下简单的类:
public class Person {
private String name;
private int age;
// Constructor, getters, setters
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
在这个Person类中,equals方法基于name和age字段进行比较,而 hashCode方法则使用Objects.hash生成哈希码。
即使我们尽力避免哈希碰撞,但在实际应用中,不同的对象可能会有相同的 hashCode。例如:
Person person1 = new Person("Alice", 30);
Person person2 = new Person("Bob", 25);
System.out.println(person1.equals(person2)); // false
System.out.println(person1.hashCode() == person2.hashCode()); // 有可能是 true
尽管person1和person2不相等(因为name和age不同),它们的hashCode 仍然有可能相等。
结论
回答原问题:“两个对象不相等,hashCode有没有可能相等?”答案是有可能。这被称为哈希碰撞,是因为hashCode返回值的范围有限(32 位整数),而可能的对象数目远远超出这个范围。
理解这一点对编写高效和正确的哈希表实现非常重要。在实际开发中,尽量设计一个好的 hashCode 方法,来减少碰撞,提高哈希表的性能。同时,始终确保遵守 equals 和 hashCode 方法的契约,以保证程序的正确性。

浙公网安备 33010602011771号