Java HashSet示例
Java中的HashSet是Java Collections框架的一部分,并且是Java应用程序中最常用的Set实现之一。 HashSet类扩展AbstractSet类,并实现Set,Cloneable和Serializable接口。 HashSet由HashMap实例支持,这意味着HashSet类在内部使用HashMap来存储其元素。
Java中HashSet的功能
这篇文章中讨论的HashSet的一些功能如下:
HashSet仅存储唯一元素。
HashSet是一个无序集合,这意味着插入顺序不会像ArrayList中那样维护。
Java中的HashSet允许为null。
HashSet不是线程安全的。
HashSet的迭代器方法返回的迭代器是快速失败的。这意味着,如果在创建迭代器之后的任何时候修改了集合,则除了通过迭代器自己的remove方法之外,它会以任何方式进行修改,迭代器都会引发ConcurrentModificationException。
Java HashSet构造函数
Java中的HashSet类具有4个构造函数。
HashSet()–此构造函数构造一个新的空集;支持的HashMap实例具有默认的初始容量(16)和负载因子(0.75)。
HashSet(int initialCapacity)–此构造函数构造一个新的空集合;支持的HashMap实例具有指定的初始容量和默认负载因子(0.75)。
HashSet(int initialCapacity,float loadFactor)–此构造函数构造一个新的空集合;支持的HashMap实例具有指定的初始容量和指定的负载系数。
HashSet(Collection <?extends E> c)–此构造函数构造一个新集合,其中包含指定集合中的元素。
HashSet的容量和负载因子
如前所述,Java中的HashSet类在内部使用HashMap来存储其元素。 HashMap依次使用Node类型的数组存储元素。如果在创建HashSet时未指定任何容量,则该数组的默认初始容量为16.
在HashMap中,使用存储桶的概念,因此将数组的每个索引概念化为一个存储桶。因此,总共有16个水桶。对于添加到HashSet的每个值,将基于该哈希值计算一个哈希,以选择这些存储桶中的一个存储元素。这样,HashSet能够为基本操作(如添加,删除,包含和大小)提供恒定的时间性能。
负载因子提供HashSet存储的阈值。一旦达到阈值,容量就会增加一倍。默认负载因子为0.75,这意味着如果使用了容量的75%,则将调整HashSet的大小。
要了解有关Java中HashSet内部实现的更多信息,请参阅此帖子。
创建HashSet的Java示例
我们来看一个基本示例,其中创建了一个HashSet并向其中添加了元素。然后显示添加的元素。
import java.util.HashSet; import java.util.Set; public class HashSetDemo { public static void main(String[] args) { Set<String> capitalSet = new HashSet<String>(); // adding elements capitalSet.add("New Delhi"); capitalSet.add("Lisbon"); capitalSet.add("Buenos Aires"); capitalSet.add("Beijing"); // Displaying set elements for(String capital : capitalSet){ System.out.println("Capital city- " + capital); } } }
输出:
Capital city- Beijing Capital city- New Delhi Capital city- Lisbon Capital city- Buenos Aires
如我们所见,使用此语句创建了默认容量的HashSet。
Set<String> capitalSet = new HashSet<String>();
现在,所有Collections类都是通用的,因此我们可以在开始时指定将在Set中存储哪种类型的元素。本示例中使用的Set只能存储字符串。
从输出中,我们可以看到在HashSet中未维护插入顺序。
HashSet类中的方法
这是Java中HashSet类中的一些方法的列表。
add(E e)–将指定的元素添加到该集合(如果尚不存在)。
clear()–从此集合中删除所有元素。
clone()–返回此HashSet实例的浅表副本:元素本身未克隆。
contains(Object o)–如果此集合包含指定的元素,则返回true。
isEmpty()–如果此集合不包含任何元素,则返回true。
iterator()–返回对此集合中的元素进行迭代的迭代器。
remove(Object o)–从指定的元素集中删除指定的元素(如果存在)。
size()–返回此集合中元素的数量。
spliterator()–在此集合中的元素上创建后绑定和故障快速的Spliterator。
HashSet中不允许重复
public class HashSetDemo { public static void main(String[] args) { Set<String> capitalSet = new HashSet<String>(); // adding elements capitalSet.add("New Delhi"); capitalSet.add("Lisbon"); capitalSet.add("Buenos Aires"); capitalSet.add("Beijing"); // added again capitalSet.add("New Delhi"); System.out.println("HashSet size-- " + capitalSet.size()); // Displaying set elements for(String capital : capitalSet){ System.out.println("Capital city- " + capital); } } }
输出:
HashSet size-- 4 Capital city- Beijing Capital city- New Delhi Capital city- Lisbon Capital city- Buenos Aires
如我们所见,即使两次添加了"新德里",也只会插入一次。 HashSet的大小也为4.
HashSet中允许插入Null
我们可以在HashSet中插入null,但只能添加一次。在下面的示例中,null被添加了两次,在输出中我们可以看到它仅被插入了一次。
public class HashSetDemo { public static void main(String[] args) { Set<String> capitalSet = new HashSet<String>(); // adding elements capitalSet.add(null); capitalSet.add("New Delhi"); capitalSet.add("Lisbon"); capitalSet.add("Buenos Aires"); capitalSet.add("Beijing"); capitalSet.add(null); System.out.println("HashSet size-- " + capitalSet.size()); // Displaying set elements for(String capital : capitalSet){ System.out.println("Capital city- " + capital); } } }
输出:
HashSet size-- 5 Capital city- null Capital city- Beijing Capital city- New Delhi Capital city- Lisbon Capital city- Buenos Aires
从HashSet中删除元素的示例代码
public class HashSetDemo { public static void main(String[] args) { Set<String> capitalSet = new HashSet<String>(); // adding elements capitalSet.add("New Delhi"); capitalSet.add("Lisbon"); capitalSet.add("Buenos Aires"); capitalSet.add("Beijing"); capitalSet.remove("Buenos Aires"); // Displaying set elements for(String capital : capitalSet){ System.out.println("Capital city- " + capital); } // Removing all elements capitalSet.clear(); System.out.println("HashSet size after clearing -- " + capitalSet.size()); } }
输出:
Capital city- Beijing Capital city- New Delhi Capital city- Lisbon HashSet size after clearing – 0
Java HashSet迭代器示例
我们可以使用迭代器来迭代HashSet。我们可以使用HashSet类的iterator()方法获取Iterator。 HashSet的迭代器方法返回的迭代器是快速失败的。如果在创建迭代器之后的任何时候修改了集合,则除了通过迭代器自己的remove方法以外,都可以通过其他方式修改该集合,否则迭代器将抛出ConcurrentModificationException。
请参阅在Java中迭代HashSet的不同方法,以查看在Java中遍历HashSet的不同方法。
让我们尝试举例说明一下。在代码中,使用迭代器迭代HashSet时,我们将尝试使用HashSet的remove()方法而非迭代器的remove方法来删除元素。
public class HashSetDemo { public static void main(String[] args) { Set<String> capitalSet = new HashSet<String>(); // adding elements capitalSet.add("New Delhi"); capitalSet.add("Lisbon"); capitalSet.add("Buenos Aires"); capitalSet.add("Beijing"); Iterator<String> itr = capitalSet.iterator(); while(itr.hasNext()){ String capital = itr.next(); System.out.println("Capital city- " + capital); if(capital.equals("Lisbon")){ capitalSet.remove(capital); } } } }
如我们所见,当我们尝试使用迭代器对HashSet进行结构化修改时,会抛出ConcurrentModificationException异常。
输出:
Capital city- Beijing Capital city- New Delhi Capital city- Lisbon Exception in thread "main" java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextNode(Unknown Source) at java.util.HashMap$KeyIterator.next(Unknown Source) at com.theitroad.HashSetDemo.main(HashSetDemo.java:19)
使用迭代器的remove方法
public class HashSetDemo { public static void main(String[] args) { Set capitalSet = new HashSet(); // adding elements capitalSet.add("New Delhi"); capitalSet.add("Lisbon"); capitalSet.add("Buenos Aires"); capitalSet.add("Beijing"); Iterator itr = capitalSet.iterator(); while(itr.hasNext()){ String capital = itr.next(); System.out.println("Capital city- " + capital); if(capital.equals("Lisbon")){ itr.remove(); } } System.out.println("** After element removal **"); // Displaying set elements for(String capital : capitalSet){ System.out.println("Capital city- " + capital); } } }
输出:
Capital city- Beijing Capital city- New Delhi Capital city- Lisbon Capital city- Buenos Aires ** After element removal ** Capital city- Beijing Capital city- New Delhi Capital city- Buenos Aires
如我们所见,使用迭代器的remove方法,可以在HashSet进行迭代时删除元素。
HashSet不是线程安全的
Java中的HashSet不是线程安全的。如果在多线程环境中使用HashSet,在该环境中HashSet的实例在许多线程之间共享,则应在外部对其进行同步。为了同步Set,可以使用Collections.synchronizedSet()方法,该方法将由传递的集支持的同步集返回到此方法。
例如
Set tempSet = Collections.synchronizedSet(capitalSet);
在此处查看在Java中同步HashSet的示例如何在Java中同步HashSet