面试官提问:
你能解释一下
HashSet
的工作原理吗?
标准回答:
HashSet
是基于 HashMap
实现的,它是一个不允许存储重复元素的集合。
工作机制:
-
HashSet
内部使用HashMap
存储元素,每个元素作为HashMap
的 key,value 则是一个固定的dummy
对象(通常是PRESENT
)。 -
当我们向
HashSet
添加元素时,它会调用hashCode()
计算哈希值,并决定存储位置。 -
如果哈希值冲突(即两个对象
hashCode()
相同),HashSet
会调用equals()
方法检查对象是否相同。 -
如果
equals()
返回true
,则认为是重复元素,不会存入集合。 -
HashSet
不保证元素的顺序,因为它基于哈希表实现。
面试官可能的深入问题
1. HashSet
如何处理重复元素?
-
通过
hashCode()
计算存储位置,如果hashCode()
相同,再调用equals()
进行比对。 -
只有当
hashCode()
相同且equals()
返回true
时,HashSet
才认为是重复元素,不会存储。
2. HashSet
的 add()
方法如何实现?
HashSet
内部的 add()
方法实际调用的是 HashMap.put(key, PRESENT)
。
示例代码:
import java.util.HashSet;
class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int hashCode() {
return name.hashCode() + age;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj instanceof Person) {
Person other = (Person) obj;
return this.name.equals(other.name) && this.age == other.age;
}
return false;
}
@Override
public String toString() {
return name + " (" + age + ")";
}
}
public class HashSetExample {
public static void main(String[] args) {
HashSet<Person> set = new HashSet<>();
set.add(new Person("Alice", 25));
set.add(new Person("Bob", 30));
set.add(new Person("Alice", 25)); // 由于 hashCode 和 equals 相同,不会被添加
System.out.println(set); // 只包含两个元素
}
}
3. HashSet
是如何保证唯一性的?
-
依赖
hashCode()
和equals()
方法。 -
hashCode()
决定存储位置,equals()
确保内容相同的对象不会重复存储。
4. HashSet
的底层数据结构是什么?
-
Java 8 及以前:基于
HashMap
,底层采用 数组 + 链表 实现。 -
Java 8 及以后:如果链表长度超过 8,链表会转换为 红黑树,提高查询效率。
5. HashSet
和 TreeSet
的区别?
特性 | HashSet | TreeSet |
---|---|---|
底层结构 | HashMap | TreeMap (红黑树) |
元素排序 | 无序 | 按自然顺序或 Comparator 排序 |
插入/删除 | O(1) | O(log N) |
适用场景 | 需要快速去重 | 需要排序的数据集合 |
总结
-
HashSet
基于HashMap
,不允许重复元素。 -
依赖
hashCode()
和equals()
方法来检查重复性。 -
不保证顺序,但能提供 O(1) 时间复杂度 的查找效率。
-
Java 8 之后,当哈希冲突严重时,链表转换为红黑树,提高性能。
在实际开发中,如果不需要排序且想要快速去重,推荐使用 HashSet
,如果需要排序,则选择 TreeSet
。
如果觉得这篇博客对你有帮助,记得点赞 ⭐、收藏 📌、关注 🚀!