HashSet中hashCode 与 equals 的关系?
hashCode 方法:返回对象的哈希码(一个整数)。hashCode 方法用于在哈希表中确定对象的存储位置。当向 HashSet 添加一个新对象时,Java 会先调用该对象的 hashCode 方法来计算出哈希码,用来定位对象在哈希表中的存储桶(bucket)。
equals 方法:用于判断两个对象是否在逻辑上相等。当两个对象的哈希码相同(即它们可能在同一个存储桶中),Java 会进一步使用 equals 方法来检查这些对象是否真的是相等的。
hashCode 与 equals 的规则
为了保证 HashSet 正常工作,必须遵循以下规则:
-
相等的对象必须有相同的哈希码:如果两个对象通过 equals 方法比较是相等的,那么它们的 hashCode 方法必须返回相同的整数值。这是为了保证当对象被放入 HashSet 时,它们被放在同一个存储桶中。
-
不相等的对象可以有相同的哈希码:两个对象即使 hashCode 相同,也不意味着它们是相等的;这只是意味着它们可能会被放在同一个存储桶中。此时,HashSet 会使用 equals 方法进一步检查它们是否相等。
举例说明
假设我们有一个简单的类 Person,根据它的 id 和 name 来判断两个对象是否相等。
class Person {private int id;private String name;public Person(int id, String name) {this.id = id;this.name = name;}// 重写 hashCode 方法@Overridepublic int hashCode() {return id; // 根据id生成哈希码}// 重写 equals 方法@Overridepublic boolean equals(Object obj) {if (this == obj) return true; // 如果是同一个对象,返回trueif (obj == null || getClass() != obj.getClass()) return false;Person person = (Person) obj;return id == person.id && name.equals(person.name); // 根据id和name判断是否相等}@Overridepublic String toString() {return "Person{id=" + id + ", name='" + name + "'}";}
}
使用 HashSet 的例子:
import java.util.HashSet;public class Main {public static void main(String[] args) {HashSet<Person> people = new HashSet<>();Person p1 = new Person(1, "Alice");Person p2 = new Person(1, "Alice"); // 同样的id和namePerson p3 = new Person(2, "Bob");people.add(p1);people.add(p2); // p2 和 p1 相等,HashSet 中不应该有重复people.add(p3);System.out.println(people); // 输出:[Person{id=1, name='Alice'}, Person{id=2, name='Bob'}]}
}
在这个例子中:
- p1 和 p2 有相同的 id 和 name。因此,它们的 hashCode 相同(都是1),并且 equals 方法返回 true,表示它们是相等的对象。
- 当我们将 p2 添加到 HashSet 时,HashSet 先计算它的哈希码(1),发现 p1 的哈希码也是1,于是进一步使用 equals 方法进行比较,结果为 true。因此,HashSet 认为 p2 是重复的对象,不会将它添加进去。
- p3 的 id 不同(2),所以 hashCode 也不同。当 p3 被添加到 HashSet 时,HashSet 直接将其插入,因为没有找到哈希码相同的对象。