在 Java 中,hashCode
和 equals
方法是密切相关的,它们通常在自定义类中一起被重写,以确保对象的相等性检查和哈希表(如 HashMap
、HashSet
等)的正确行为。以下是它们之间的关系和重写时需要遵守的规则:
-
一致性:如果两个对象通过
equals
方法判断是相等的,那么这两个对象调用hashCode
方法必须产生相同的整数值。换句话说,如果a.equals(b)
返回true
,那么a.hashCode()
必须等于b.hashCode()
。 -
等效性:如果两个对象的
hashCode
方法返回相同的值,它们并不一定相等。也就是说,hashCode
方法返回相同的值并不意味着equals
方法返回true
。这仅仅是一个充分不必要条件。 -
不变性:在对象的生命周期内,只要对象的状态没有发生变化(即
equals
方法用来判断相等性的状态没有变化),hashCode
方法返回的值应该是一致的。如果对象的状态发生变化,并且这种变化会影响equals
方法的比较结果,那么hashCode
方法的返回值也必须相应地变化。 -
效率:
hashCode
方法应该尽量均匀地分布哈希值,以减少哈希冲突,提高哈希表的性能。
为什么需要这样的关系?
这种关系对于哈希表的实现至关重要。哈希表通过将对象的 hashCode
值映射到一个数组索引来存储对象,这样可以快速地检索对象。如果两个对象相等(即 equals
返回 true
),它们必须映射到同一个数组索引,否则哈希表就无法通过键来查找对应的值。
示例
假设我们有一个 Person
类,它有两个属性:name
和 age
。如果我们想要在哈希表中存储 Person
对象,我们需要重写 equals
和 hashCode
方法:
import java.util.Objects;
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@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);
}
}
在这个例子中,equals
方法检查两个 Person
对象是否具有相同的 name
和 age
。hashCode
方法使用 Objects.hash
工具方法来生成一个基于 name
和 age
的哈希值。这样,具有相同 name
和 age
的 Person
对象将具有相同的哈希值,并且它们被认为是相等的。
结论
正确地重写 hashCode
和 equals
方法对于确保 Java 集合框架的正确性和效率至关重要。如果你重写了 equals
方法,那么通常也应该重写 hashCode
方法,以保持它们之间的一致性。