java hashset 判断包含元素时,底层会调用该元素的 equals() 方法进行比较。如果两个对象通过 equals() 返回 true,则判定为包含。对于自定义类,必须重写 equals() 和 hashcode() 才能保证逻辑正确。

HashSet 如何验证对象相等性
验证过程分为两步:先计算哈希值定位桶,再比较内容。第一步调用 hashCode() 获取哈希码,第二步在发生碰撞的桶中遍历链表或红黑树,逐个调用 equals() 检查是否相等。

import java.util.HashSet;
public class Main {
public static void main(String[] args) {
HashSet<person> set = new HashSet();
Person p1 = new Person("Alice", 30);
Person p2 = new Person("Alice", 30);
set.add(p1);
System.out.println(set.contains(p2)); // true
}
}
class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person)) return false;
Person person = (Person) o;
return age == person.age && name.equals(person.name);
}
@Override
public int hashCode() {
return 31 * name.hashCode() + age;
}
}</person>
哈希冲突时的处理机制
当不同对象的 hashCode() 相同时,它们会被放入同一个桶中。此时 contains() 不会直接返回 false,而是进入线性扫描阶段,依次调用 equals() 直到找到匹配项或遍历结束。

import java.util.HashSet;
class BadHash {
String val;
public BadHash(String val) { this.val = val; }
@Override public int hashCode() { return 1; } // 故意制造冲突
@Override public boolean equals(Object o) {
return o instanceof BadHash && ((BadHash)o).val.equals(this.val);
}
}
public class TestCollision {
public static void main(String[] args) {
HashSet<badhash> set = new HashSet();
set.add(new BadHash("A"));
System.out.println(set.contains(new BadHash("A"))); // true
System.out.println(set.contains(new BadHash("B"))); // false
}
}</badhash>
未重写 hashCode() 会导致什么结果
如果只重写了 equals() 而未重写 hashCode(),默认使用 Object 类的哈希实现(基于内存地址)。这会导致即使两个对象逻辑相等,它们的哈希值也不同,从而被分配到不同的桶中。contains() 只会检查目标哈希值对应的桶,因此永远找不到已添加的对象。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











