为什么一个对象重写了equals必须也重写hashCode

打印 上一主题 下一主题

主题 775|帖子 775|积分 2325

一言以蔽之:重写 equals 方法是为了比较对象的内容是否相等,重写 hashCode 方法是为了保证对象在哈希表等数据结构中的正确性。
 
1、在 Java 中,如果一个类重写了 equals 方法,则必须同时重写 hashCode 方法。这是因为在 Java 中,对象的 hashCode 值用于在哈希表(Hash Table)等数据结构中进行快速查找,而哈希表的实现原理是根据对象的 hashCode 值进行散列(Hash),所以如果两个对象的 equals 方法返回 true,则它们的 hashCode 值也必须相等,否则可能会导致哈希表的查询等操作出现错误结果。
以下是一个示例,演示了为什么需要同时重写 equals 和 hashCode 方法:
  1. public class Person {
  2.     private String name;
  3.     private int age;
  4.     public Person(String name, int age) {
  5.         this.name = name;
  6.         this.age = age;
  7.     }
  8.     @Override
  9.     public boolean equals(Object obj) {
  10.         if (this == obj) return true;
  11.         if (!(obj instanceof Person)) return false;
  12.         Person person = (Person) obj;
  13.         if (age != person.age) return false;
  14.         if (name != null ? !name.equals(person.name) : person.name != null) return false;
  15.         return true;
  16.     }
  17. }
复制代码
如果只重写了 equals 方法,而没有重写 hashCode 方法,则可能会导致哈希表中出现错误的结果:
  1. Person p1 = new Person("Alice", 18);
  2. Person p2 = new Person("Alice", 18);
  3. Map<Person, String> map = new HashMap<>();
  4. map.put(p1, "Hello");
  5. // 此时尝试获取 p2 对应的值,由于没有重写 hashCode 方法,p1 和 p2 的 hashCode 值不相等
  6. // 因此,虽然 p1 和 p2 的 equals 方法返回 true,但是从哈希表中获取 p2 对应的值时却会失败
  7. String value = map.get(p2); // value 为 null
复制代码
2、下面是一个重写了 hashCode 方法的示例代码:
  1. public class Person {
  2.     private String name;
  3.     private int age;
  4.     public Person(String name, int age) {
  5.         this.name = name;
  6.         this.age = age;
  7.     }
  8.     @Override
  9.     public boolean equals(Object obj) {
  10.         if (this == obj) return true;
  11.         if (!(obj instanceof Person)) return false;
  12.         Person person = (Person) obj;
  13.         if (age != person.age) return false;
  14.         if (name != null ? !name.equals(person.name) : person.name != null) return false;
  15.         return true;
  16.     }
  17.     @Override
  18.     public int hashCode() {
  19.         int result = name != null ? name.hashCode() : 0;
  20.         result = 31 * result + age;
  21.         return result;
  22.     }
  23. }
复制代码
在上面的示例代码中,hashCode 方法重写的实现逻辑与 equals 方法的实现逻辑是一致的,都是比较 Person 对象的两个属性 name 和 age 是否相等,如果相等则返回相同的 hashCode 值。
需要注意的是,这里的 31 是一个质数,它的作用是为了避免哈希冲突,因为 31 的乘法运算比较快,而且相对来说能够更加均匀地散布哈希值,从而减少哈希冲突的发生。
重写了 hashCode 方法之后,就可以保证在哈希表等数据结构中,同一个对象的 hashCode 值不变,不同对象的 hashCode 值不同,从而能够正确地进行查找和比较操作。
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

张春

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表