当我们在Java中创建一个类,并希望在集合类(如HashMap
、HashSet
等)中使用这个类的实例时,通常需要重写equals
方法。但为什么要同时重写hashCode
方法呢?
我们先了解一下equal和hashCode。
equal 和 hashCode 是什么?
在Java中,equals
方法是Object
类中定义的一个方法,用于比较两个对象是否在逻辑上相等。
为什么要重写equals
方法
默认情况下,equals
方法在Object
类中的实现是比较两个对象的引用是否相等,即它们是否指向内存中的同一位置。这意味着,如果你创建了两个相同内容的对象,它们的equals
方法可能返回false
,因为它们在内存中的位置不同。但在很多情况下,我们更关心的是对象的内容是否相等,而不是对象的引用是否相等。
hashCode
是 Java 中 Object
类的一个方法,用于返回对象的哈希码。哈希码是一个32位的整数,它代表了对象的内存地址经过哈希算法生成的值。每个对象都有一个对应的哈希码。哈希码的主要作用是在集合类中,比如HashMap
和HashSet
等,用于快速定位对象的位置。
在 Java 中,hashCode
方法的定义在 Object
类中,但是它通常会被子类重写以提供更有意义的哈希码。如果两个对象根据 equals
方法是相等的,那么它们的 hashCode
方法应该返回相同的值。虽然相等的对象必须具有相等的哈希码,但相等哈希码的对象并不一定相等。
那么为什么需要重写hashCode方法呢?
默认情况下,两个相等的对象(根据equals
方法的定义)的哈希码可能是不相等的,这违反了集合的规则。但是我们希望相等的对象具有相等的哈希码。
集合类在处理冲突或者寻找对象时,会先根据哈希码定位到可能的位置,然后再使用equals
方法来准确地找到对象。如果两个相等的对象的哈希码不同,它们可能会被放置在不同的位置,导致无法正确地找到对象。
下面是一个示例:
public static void main(String[] args) { Person p1=new Person("张三",21); Person p2=new Person("张三",21); Set<Person> set=new HashSet<>(); set.add(p1); System.out.println(set.contains(p2));//是否包含p2对象,返回false }
尽管 p1 和 p2的内容相同,但由于它们具有不同的哈希码,set.contains(p2) 返回 false。这是因为哈希表无法正确定位到p2。
为什么要保持equals和hashCode的一致性?
当我们在集合类中使用对象时,通常是先使用hashCode
定位到对象的位置,然后再使用equals
方法确保找到的对象是真正相等的。为了保持这一过程的正确性,equals
和hashCode
方法之间需要保持一致性。
一致性规则
如果两个对象根据equals
方法是相等的,那么它们的hashCode
方法应该返回相同的值。反之,如果两个对象的hashCode
相等,它们不一定要相等。
重写hashcode和equals示例
public class Student { private String name; private int age; // 构造方法、其他方法等... @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Student student = (Student) o; if (age != student.age) return false; return name != null ? name.equals(student.name) : student.name == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + age; return result; } }
在这个示例中,equals
方法根据name
和age
的内容来判断两个Student
对象是否相等,而hashCode
方法则根据name
和age
的内容生成哈希码。这样,如果两个Student
对象根据equals
方法是相等的,它们的hashCode
值也会相等,从而保持了一致性。