前言
HashSet 基于 HashMap 来实现的,是一个不允许有重复元素的集合。
HashSet是Java集合框架中实现了Set接口的一个类,它使用哈希表来存储元素。以下是关于HashSet的一些说明:
元素唯一性: HashSet保证集合中的元素是唯一的,即不允许重复元素。如果试图向HashSet中添加一个已经存在的元素,该操作将被忽略。
无序性: HashSet不保证元素的顺序。与List不同,HashSet不维护元素的插入顺序。如果需要有序集合,可以考虑使用LinkedHashSet,它保留了元素的插入顺序。
允许null元素: HashSet允许存储null元素,但只能存储一个null,因为集合中的元素是唯一的。
基于哈希表: HashSet的内部实现是基于哈希表的。哈希表是一种高效的数据结构,它通过哈希函数将元素映射到数组的特定位置,以实现快速的插入、删除和查找操作。
不同步: HashSet不是线程安全的。如果多个线程同时访问一个HashSet实例并且至少有一个线程修改了集合,那么它必须在外部进行同步。
构造方法
使用无参构造方法,如
HashSet<String> set1 = new HashSet<>();
使用带容量和负载因子的构造方法,如
HashSet<String> set2 = new HashSet(int initialCapacity, float loadFactor);
HashSet<String> set2 = new HashSet<>(20, 0.8f)
容量(Capacity):
容量指的是哈希表底层数组的大小,即哈希桶的数量。在 HashSet 中,容量决定了可以存储多少个元素。初始时,HashSet 的容量由构造方法中的初始容量(initialCapacity)指定,默认为 16。
负载因子(Load Factor):
负载因子是一个衡量哈希表充满程度的值。它是一个浮点数,通常取值在 0 到 1 之间。在 HashSet 中,负载因子由构造方法中的负载因子(loadFactor)指定,默认为 0.75。
负载因子的作用是在哈希表中达到一定充满程度时触发扩容操作。当哈希表中的元素数量达到容量乘以负载因子时,哈希表会自动进行扩容,以保持哈希表的性能。扩容一般会导致重新计算哈希值并重新分配元素到新的更大的数组中。
例如,如果构造方法中指定了初始容量为 16,负载因子为 0.75,那么哈希表的初始容量就是 16,负载因子为 0.75。当哈希表中的元素数量达到 16 * 0.75 = 12 时,就会触发扩容操作,将容量翻倍为 32,并重新分配元素到新的数组中。这有助于平衡哈希表的性能和空间利用率。
查看源码可以发现HashSet 实际上是基于 HashMap 实现的。在Java中,HashSet 类实现了 Set 接口,而它的内部实现使用了 HashMap。
HashSet的一些常用方法
添加元素:add(E e): 将指定的元素添加到集合中。如果元素已经存在,添加操作不会产生影响。
删除元素:remove(Object o): 从集合中移除指定的元素。
判断是否包含元素:contains(Object o): 判断集合中是否包含指定的元素。
获取集合大小:size(): 返回集合中元素的数量。
清空集合:clear(): 清空集合中的所有元素。
判断集合是否为空:isEmpty(): 判断集合是否为空。
遍历集合:使用迭代器(Iterator)或者增强型 for 循环遍历集合中的元素。
获取集合的哈希码:hashCode(): 返回集合的哈希码。
复制集合:clone(): 返回集合的浅拷贝。
元素唯一性
例子
import java.util.HashSet;
import java.util.Set;
public class Test {
public static void main(String[] args) {
// 创建一个HashSet
Set<String> Set = new HashSet<>();
// 添加元素到HashSet
Set.add("A");
Set.add("B");
Set.add("C");
Set.add("A"); // 重复元素,不会被添加
// 打印HashSet的内容
System.out.println("HashSet Elements: " + Set);
}
}
运行结果
无序性
例子
import java.util.HashSet;
import java.util.Set;
public class Test {
public static void main(String[] args) {
// 创建一个HashSet
Set<String> Set = new HashSet<>();
// 添加元素到HashSet
Set.add("D");
Set.add("B");
Set.add("C");
Set.add("A"); // 重复元素,不会被添加
// 打印HashSet的内容
for (String element : Set) {
System.out.println(element);
}
}
}
运行结果
允许null元素
例子
import java.util.HashSet;
import java.util.Set;
public class Test {
public static void main(String[] args) {
// 创建一个HashSet
Set<Integer> Set = new HashSet<>();
// 添加元素到HashSet
Set.add(null);
Set.add(1);
Set.add(2);
Set.add(3); // 重复元素,不会被添加
// 打印HashSet的内容
for (Integer element : Set) {
System.out.println(element);
}
}
}
运行结果
总结
学习 HashSet 使我深刻理解了哈希表的运作原理和优势,为我的数据结构认知提供了全新的视角。通过熟练使用 HashSet,我不仅能够更灵活高效地处理编程任务,还培养了处理数据唯一性的技能。这种能力在许多实际应用中都显得尤为重要。通过理解 HashSet 中不同的冲突解决策略,例如开放寻址法和链表法,我学会了优化和调整数据结构,以提高程序性能。总的来说,学习 HashSet 不仅是对 Java 集合框架的深入掌握,更是一次全面提升编程和数据处理能力的宝贵经历,为我的职业发展打下了坚实的基础。