跳转到内容

Java HashSet

来自代码酷
Admin留言 | 贡献2025年4月30日 (三) 18:53的版本 (Page creation by admin bot)

(差异) ←上一版本 | 已核准修订 (差异) | 最后版本 (差异) | 下一版本→ (差异)

模板:Note

Java HashSet[编辑 | 编辑源代码]

HashSet是Java集合框架(Java Collections Framework)中Set接口的一个实现类,它使用哈希表(Hash Table)作为存储结构。HashSet不保证元素的顺序,且不允许重复元素。它是基于HashMap实现的,但只存储键(key)而不存储值(value)。

核心特性[编辑 | 编辑源代码]

  • 无序性:元素存储顺序与插入顺序无关。
  • 唯一性:不允许重复元素(基于equals()hashCode()方法判断)。
  • 高效性:添加、删除和查找操作的平均时间复杂度为O(1)。
  • 非线程安全:需手动同步或使用Collections.synchronizedSet()包装。

实现原理[编辑 | 编辑源代码]

HashSet内部通过HashMap实现。当添加元素时,元素作为HashMap的键(key),而值(value)统一为一个静态常量PRESENT

classDiagram class HashSet { -map: HashMap +add(e: E): boolean +remove(o: Object): boolean +contains(o: Object): boolean } class HashMap { +put(key: K, value: V): V } HashSet --> HashMap : 内部委托

基本操作示例[编辑 | 编辑源代码]

以下代码展示HashSet的常见操作:

import java.util.HashSet;

public class HashSetExample {
    public static void main(String[] args) {
        // 创建HashSet
        HashSet<String> languages = new HashSet<>();

        // 添加元素
        languages.add("Java");
        languages.add("Python");
        languages.add("C++");
        System.out.println("初始集合: " + languages); // 输出顺序可能不同

        // 重复元素测试
        boolean added = languages.add("Java");
        System.out.println("能否重复添加'Java'? " + added); // false

        // 删除元素
        languages.remove("C++");
        System.out.println("删除后: " + languages);

        // 检查元素存在性
        System.out.println("包含Python? " + languages.contains("Python"));
    }
}

输出示例

初始集合: [Java, C++, Python]
能否重复添加'Java'? false
删除后: [Java, Python]
包含Python? true

关键方法详解[编辑 | 编辑源代码]

方法 描述 时间复杂度
boolean add(E e) 添加元素(若不存在) O(1)
boolean remove(Object o) 删除指定元素 O(1)
boolean contains(Object o) 检查元素是否存在 O(1)
int size() 返回元素数量 O(1)
void clear() 清空集合 O(n)

哈希冲突处理[编辑 | 编辑源代码]

当不同对象的哈希码(通过hashCode()计算)相同时,HashSet使用链地址法解决冲突。Java 8后,当链表长度超过阈值(默认为8)时,链表会转换为红黑树以提高性能。

冲突处理公式: 存储位置=hash(key)mod容量

实际应用案例[编辑 | 编辑源代码]

场景:统计一篇文章中出现的唯一单词数量。

import java.util.HashSet;
import java.util.Arrays;

public class WordCounter {
    public static void main(String[] args) {
        String text = "Java is to JavaScript what car is to carpet";
        String[] words = text.split("\\s+"); // 按空格分割

        HashSet<String> uniqueWords = new HashSet<>(Arrays.asList(words));
        System.out.println("唯一单词数量: " + uniqueWords.size());
        System.out.println("单词列表: " + uniqueWords);
    }
}

输出

唯一单词数量: 8
单词列表: [car, carpet, what, Java, is, to, JavaScript, car]

性能优化建议[编辑 | 编辑源代码]

1. 初始容量:构造时指定预期大小(避免频繁扩容):

   HashSet<Integer> numbers = new HashSet<>(100); // 初始容量100

2. 负载因子:调整扩容阈值(默认0.75):

   new HashSet<>(100, 0.6f); // 当60%满时扩容

3. 重写hashCode():自定义对象作为元素时需正确实现hashCode()equals()

与TreeSet对比[编辑 | 编辑源代码]

特性 HashSet TreeSet
数据结构 哈希表 红黑树
顺序 无序 自然排序/自定义排序
时间复杂度 O(1) O(log n)
允许null 否(除非自定义比较器)

常见问题[编辑 | 编辑源代码]

Q: 为什么我的自定义对象无法正确去重? A: 需确保重写了equals()hashCode()方法,且满足:

  • 如果a.equals(b)为true,则a.hashCode() == b.hashCode()
  • 同一对象的hashCode值在生命周期内应保持一致

进阶话题[编辑 | 编辑源代码]

  • 弱一致性迭代器:迭代过程中修改集合可能导致ConcurrentModificationException
  • 并行处理:使用Collections.synchronizedSet()ConcurrentHashMap.newKeySet()实现线程安全

页面模块:Message box/ambox.css没有内容。