先根据对象的hashCode进行初步判断,再通过equals方法进一步确认。
- 计算hashCode:当两个对象加入HashSet中,会先调用对象的hashcode方法计算哈希码。
如果哈希码不同,则说明两个对象不相等,HashSet会将它们存储在不同的位置。 - 哈希码相等的情况:如果两个对象的哈希码相等,则会进一步调用equals方法来判断它们是否相等。
如果equals方法返回true,则HashSet不会将第二个对象加入其中,因为HashSet不能存储重复的元素。
如果返回false,则认为这两个对象不相等,HashSet会将第二个对象加入到集合中,与第一个对象在同一个哈希桶中。
注意:
为了保证 HashSet 能够正确地判断对象的相等性,在自定义类中重写 hashCode 方法时,也必须重写 equals 方法,并且要遵循以下原则:
- 如果两个对象根据 equals 方法比较是相等的,那么它们的 hashCode 方法返回的值必须相同。
- 如果两个对象的 hashCode 方法返回的值相同,但它们根据 equals 方法比较不一定是相等的(即可能存在哈希冲突)。
import java.util.HashSet;
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 重写equals方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && name.equals(person.name);
}
// 重写hashCode方法
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
public class HashSetEqualityExample {
public static void main(String[] args) {
HashSet<Person> set = new HashSet<>();
Person p1 = new Person("Alice", 25);
Person p2 = new Person("Alice", 25);
set.add(p1);
set.add(p2);
System.out.println(set.size()); // 输出 1,因为p1和p2被认为是相等的对象
}
}
Person 类重写了 equals 方法和 hashCode 方法,根据 name 和 age 来判断两个 Person 对象是否相等。当向 HashSet 中添加两个具有相同 name 和 age 的 Person 对象时,HashSet 会认为它们是相等的,只存储一个对象。
在执行 equals 之前会不会执行 hashCode方法?
在执行equals
方法之前,通常会先执行hashCode
方法。
HashSet
等集合在判断元素是否相等时,是先通过hashCode
方法计算对象的哈希码,根据哈希码来确定对象在集合中的存储位置。如果两个对象的哈希码不同,那么它们肯定不相等,就不会再调用equals
方法进行比较。
只有当两个对象的哈希码相同时,才会进一步调用equals
方法来判断它们在逻辑上是否相等。
这种先比较hashCode
再比较equals
的方式可以提高比较效率,避免不必要的equals
方法调用,因为hashCode
的计算通常比equals
方法的比较要快。