原文: https://howtodoinjava.com/java/collections/java-hashset/
Java HashSet类实现了Set接口,由哈希表(实际上是HashMap实例)支持。 如果不对迭代顺序提供任何保证,并允许null元素。
Table of Contents1\. HashSet Hierarchy2\. HashSet Features3\. HashSet Constructors4\. HashSet Methods5\. HashSet Example6\. HashSet Usecases7\. HashSet Performance8\. Conclusion
1. HashSet层次结构
HashSet类扩展了实现Set接口的AbstractSet类。 Set接口以层次结构顺序继承Collection和Iterable接口。
public class HashSet<E> extends AbstractSet<E>
implements Set<E>, Cloneable, Serializable
{
//implementation
}

哈希集合层次结构
2. HashSet特性
- 它实现了
Set接口。 HashSet中不允许重复的值。HashSet中允许一个NULL元素。- 它是无序集合,并且不保证集合的迭代顺序。
- 此类为基本操作(添加,删除,包含和调整大小)提供恒定的时间性能。
HashSet不同步。 如果多个线程同时访问哈希集合,并且至少有一个线程修改了哈希集合,则必须在外部对其进行同步。- 使用
Collections.synchronizedSet(new HashSet())方法来获取同步的哈希集合。 - 此类的迭代器方法返回的迭代器为快速失败,并且如果在创建迭代器后的任何时间修改了集合,则可能会抛出
ConcurrentModificationException,除了通过迭代器自己的remove()方法之外 。 HashSet还实现了Searlizable和Cloneable接口。
2.1 初始容量
初始容量表示创建哈希集合时(在支持HashMap中)的存储桶数。 如果当前大小已满,则存储桶数将自动增加。
默认初始容量为 16 。 我们可以通过在构造器HashSet(int initialCapacity)中传递默认容量来覆盖此默认容量。
2.2 负载系数
负载因子是在自动增加 HashSet 容量之前允许其充满的度量。 默认负载系数为 0.75 。
这称为阈值,等于(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY)。 当HashSet元素计数超过此阈值时,将调整HashSet的大小,并且新容量将是先前容量的两倍。
使用默认的HashSet时,内部容量为 16,负载系数为 0.75。 当表格中有 12 个元素时,存储桶数将自动增加。
3. HashSet构造器
HashSet具有四种类型的构造器:
HashSet():使用默认的初始容量(16)和默认的负载因子(0.75)初始化默认的HashSet实例。HashSet(int capcity):初始化具有指定容量和默认加载因子(0.75)的HashSet。HashSet(int capcity, float loadFactor):使用指定的初始容量和指定的负载系数初始化HashSet。HashSet(Collection c):使用与指定集合相同的元素初始化HashSet。
4. HashSet方法
public boolean add(E e):如果指定的元素尚不存在,则将其添加到Set中。 此方法在内部使用equals()方法检查重复项。 如果元素重复,则元素被拒绝,并且不替换值。public void clear():从哈希集合中删除所有元素。public boolean contains(Object o):如果哈希集合包含指定的元素则返回true,否则为false。public boolean isEmpty():如果哈希集合不包含任何元素,则返回true,否则返回false。public int size():返回哈希集合中的元素数。public Iterator<E> iterator():在此哈希集合中的元素上返回迭代器。 从迭代器返回的元素没有特定的顺序。public boolean remove(Object o):从哈希集合中删除指定的元素(如果存在)并返回true,否则返回false。public boolean removeAll(Collection <?> c):删除哈希集合中所有属于指定集合的元素。public Object clone():返回哈希集合的浅表副本。public Spliterator<E> spliterator():在此哈希集合中的元素上创建后绑定且快速失败的拆分器。
5. Java HashSet示例
5.1 HashSet添加,删除,迭代器示例
//1\. Create HashSet
HashSet<String> hashSet = new HashSet<>();
//2\. Add elements to HashSet
hashSet.add("A");
hashSet.add("B");
hashSet.add("C");
hashSet.add("D");
hashSet.add("E");
System.out.println(hashSet);
//3\. Check if element exists
boolean found = hashSet.contains("A"); //true
System.out.println(found);
//4\. Remove an element
hashSet.remove("D");
//5\. Iterate over values
Iterator<String> itr = hashSet.iterator();
while(itr.hasNext())
{
String value = itr.next();
System.out.println("Value: " + value);
}
程序输出。
[A, B, C, D, E]
true
Value: A
Value: B
Value: C
Value: E
5.2 将HashSet转换为数组示例
Java 示例,使用toArrray()方法将哈希集合转换为数组。
HashSet<String> hashSet = new HashSet<>();
hashSet.add("A");
hashSet.add("B");
hashSet.add("C");
hashSet.add("D");
hashSet.add("E");
String[] values = new String[hashSet.size()];
hashSet.toArray(values);
System.out.println(Arrays.toString(values));
程序输出:
[A, B, C, D, E]
5.3 将HashSet转换为ArrayList示例
使用 Java 8 流 API 将哈希集合转换为ArrayList的 Java 示例。
HashSet<String> hashSet = new HashSet<>();
hashSet.add("A");
hashSet.add("B");
hashSet.add("C");
hashSet.add("D");
hashSet.add("E");
List<String> valuesList = hashSet.stream().collect(Collectors.toList());
System.out.println(valuesList);
程序输出:
[A, B, C, D, E]
6. HashSet用例
HashSet非常类似于ArrayList类。 此外,它还会限制重复值。 因此,当我们有一个只需要存储不同元素的需求时,我们可以选择HashSet。
HashSet的真实用例可以存储流中的数据,其中流可能包含重复的记录,而我们仅对不同的记录感兴趣。
另一个用例是在给定的句子中找到不同的单词。
7. Java HashSet性能
HashSet类为基本操作(添加,删除,包含和大小)提供O(1)的恒定时间性能,假设哈希函数将元素正确分散在存储桶中。- 对此集合进行迭代需要的时间与
HashSet实例的大小(元素的数量)加上后备HashMap实例的“容量”(存储桶的数量)之和成比例。 因此,如果迭代性能很重要,则不要将初始容量设置得过高(或负载因子过低),这一点非常重要。
8. 总结
从上面的讨论中可以明显看出,在我们要处理重复记录的情况下,HashSet是非常有用的集合类。 它为基本操作提供了可预测的性能。
在评论中向我发送有关 Java 中 HashSet的问题。
学习愉快!
参考:
