问答题745/1053hashCode 与 equals (重要)

难度:
2021-11-02 创建

参考答案:

在 Java 中,hashCode()equals() 是用来定义对象的比较与哈希行为的两个核心方法。它们在集合框架(如 HashMapHashSet)中有着重要的作用,直接影响对象的存储和查找性能。


方法定义

  1. hashCode()

    • 返回对象的哈希码,用于确定对象在哈希表中的存储位置。
    • 定义在 Object 类中:
      1public native int hashCode();
  2. equals()

    • 用于比较两个对象是否相等。
    • 默认实现是比较对象的内存地址:
      1public boolean equals(Object obj) { 2 return (this == obj); 3}

两者的关系

Java 中规定了 hashCode()equals() 的契约关系:

  1. 如果两个对象通过 equals() 比较相等,则它们的 hashCode() 必须相等。
  2. 如果两个对象的 hashCode() 不相等,则它们一定不相等。
  3. 如果两个对象的 hashCode() 相等,它们不一定通过 equals() 比较相等。

示例:

1class Person { 2 String name; 3 4 Person(String name) { 5 this.name = name; 6 } 7 8 @Override 9 public boolean equals(Object obj) { 10 if (this == obj) return true; 11 if (obj == null || getClass() != obj.getClass()) return false; 12 Person person = (Person) obj; 13 return name.equals(person.name); 14 } 15 16 @Override 17 public int hashCode() { 18 return name.hashCode(); 19 } 20}

为什么需要两者共同作用

  1. hashCode() 提高效率:

    • 在基于哈希的数据结构(如 HashMapHashSet)中,hashCode() 用于快速找到对象所在的“桶”。
    • equals() 再进一步比较以确认对象是否相等。
  2. 单独依赖 equals() 的缺陷:

    • 如果只依赖 equals(),每次查找都需要遍历集合中的每个元素,性能较低。
    • hashCode() 的引入减少了比较次数。
  3. 哈希冲突的处理:

    • 即使 hashCode() 相等,仍可能发生冲突。此时,集合会调用 equals() 方法进一步比较。

示例:正确使用两者

1import java.util.HashSet; 2 3class Person { 4 String name; 5 6 Person(String name) { 7 this.name = name; 8 } 9 10 @Override 11 public boolean equals(Object obj) { 12 if (this == obj) return true; 13 if (obj == null || getClass() != obj.getClass()) return false; 14 Person person = (Person) obj; 15 return name.equals(person.name); 16 } 17 18 @Override 19 public int hashCode() { 20 return name.hashCode(); 21 } 22} 23 24public class Main { 25 public static void main(String[] args) { 26 HashSet<Person> set = new HashSet<>(); 27 set.add(new Person("Alice")); 28 System.out.println(set.contains(new Person("Alice"))); // 输出: true 29 } 30}

常见问题

  1. 为什么重写 equals() 后必须重写 hashCode()

    • 如果不重写 hashCode(),默认实现可能导致相等的对象有不同的哈希码,导致哈希集合(如 HashMap)无法正常工作。
  2. hashCode()equals() 没有遵守约定会怎样?

    • 导致集合行为异常。例如:HashSet 中可能出现相等对象重复存储。
  3. 如何设计 hashCode()

    • 确保均匀分布,减少冲突。
    • 使用标准工具,如 Objects.hash()Apache Commons LangHashCodeBuilder
  4. 是否可以只重写 hashCode() 而不重写 equals()

    • 不推荐。equals() 定义了对象的逻辑相等性,如果只重写 hashCode() 会导致错误的相等判断。

不重写的后果示例

错误情况:

1class Person { 2 String name; 3 4 Person(String name) { 5 this.name = name; 6 } 7} 8 9public class Main { 10 public static void main(String[] args) { 11 HashSet<Person> set = new HashSet<>(); 12 set.add(new Person("Alice")); 13 System.out.println(set.contains(new Person("Alice"))); // 输出: false 14 } 15}

修复:

1@Override 2public boolean equals(Object obj) { 3 if (this == obj) return true; 4 if (obj == null || getClass() != obj.getClass()) return false; 5 Person person = (Person) obj; 6 return name.equals(person.name); 7} 8 9@Override 10public int hashCode() { 11 return name.hashCode(); 12}

最近更新时间:2024-12-09