Java中的equals()与hashCode()
1. equals()方法与 hashCode()方法之间的约定
假设有两个对象A和B:
- 如果 A.equals(B) == true,那么 A.hashCode() 与 B.hashCode() 必须相等
- 如果 A.equals(B) == false,那么 A.hashCode() 与 B.hashCode() 不一定相等
- 如果 A.hashCode() 与 B.hashCode() 相等,A.equals(B) 返回值不一定为 true
- 如果 A.hashCode() 与 B.hashCode() 不相等,那么 A.equals(B) 一定为 false
为了保证 .equals() 和 hashCode() 方法之间的维持上述约定,重写 .equals() 方法时,必须同时重写 hashCode() 方法。虽然违反上述约定,编译和运行时都不会报错,但是在一些场景会出现逻辑错误。
2. hashCode() 的作用
- hashCode() 方法的核心作用是:为对象生成一个整数,用来加速在哈希结构(HashMap、HashSet、Hashtable 等)中的查找和存储。
为什么 hashCode() 和 equals() 需要保持一致?
-
场景 1:如果 A.equals(B) == true,那么它们应该被视为逻辑上相等的对象。此时二者的 hashCode() 必须返回相同的值,否则在使用 HashMap/HashSet 等基于哈希的集合时,可能会被放入不同的哈希桶中,导致相同的对象被存储多次,违反集合的唯一性要求。
-
场景 2:如果 A.equals(B) == false,它们的 hashCode() 可以相同(哈希碰撞)。这种情况下,它们会被放入同一个哈希桶中,但最终会通过 equals() 方法确认它们是不同的对象。
// 在下面这段代码中,如果重写了.equals() 却没重写 hashCode(),结果会是false
class Student {String id;Student(String id) { this.id = id; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (!(o instanceof Student)) return false;Student s = (Student) o;return id.equals(s.id);}// 重写 hashCode()// @Override// public int hashCode() {// return Objects.hash(id);//}
}public class TestMain {public static void main(String[] args) throws IOException {HashSet<Student> set = new HashSet<>();set.add(new Student("1001"));// 结果是 falseSystem.out.println(set.contains(new Student("1001")));}
}
总结
hashCode() 给对象生成一个整数,用来加速哈希容器(比如 HashMap)的存取。Java 规定:如果两个对象通过 .equals() 相等,它们的 hashCode() 必须一样,否则哈希结构会出错;但反过来,hashCode() 一样,不代表 .equals() 就相等。