前面我们已学习了ArrayList、LinkedList、HashMap、HashTable、TreeMap,接下来我们来学习HashSet。
首先我们对HashSet有一个整体的认识,然后学习它的源码,最后通过代码示例学会使用它。
一、HashSet基本概述
HashSet是由HashMap实现的,所以底层也是散列表(数组+链表)。
HashMap是无序的,且不允许元素重复,但HashSet允许元素为空。
HashSet是非同步的。如果多个线程同时访问一个HashSet,若其中至少一个线程修改了该set,那么就必须保持外部同步。这通常是通过封装该set的对象执行同步操作来完成的。
如果不存在这样的对象,则应该使用Collections.synchronizedSet(同步set)方法来包装set。在创建时完成该操作:
Set s = Collections.synchronizedSet(new HashSet(...));
HashSet通过Iterator()返回的迭代器也是Fail-Fast机制。
易考点:
关注点 | 结论 |
---|---|
结合底层实现的数据结构 | 由HashMap实现,散列表(数组+列表) |
集合中元素是否允许为空 | Key和value都可以为空 |
是否允许数据重复 | 不允许元素重复 |
是否有序 | 无序,是指不是按put进来的顺序 |
是否线程安全 | 非线程安全(不是同步的) |
二、HashSet的数据结构
1>HashSet与Map关系如下图:
从中可以得到:
a.HashSet继承于AbstractSet,并且实现了Set接口;
b、HashSet不允许元素重复,底层是由HashMap实现的。HashSet中哈有一个HashMap类型的成员变量map,HashSet的操作函数,都是基于map实现的。
2>HashSet的构造函数
1、默认构造函数
// 默认构造函数
public HashSet() {
// 调用HashMap的默认构造函数,创建map
map = new HashMap<E,Object>();
}
2、带集合的构造函数
// 带集合的构造函数
public HashSet(Collection<? extends E> c) {
// 创建map。
// 为什么要调用Math.max((int) (c.size()/.75f) + 1, 16),从 (c.size()/.75f) + 1 和 16 中选择一个比较大的树呢?
// 首先,说明(c.size()/.75f) + 1
// 因为从HashMap的效率(时间成本和空间成本)考虑,HashMap的加载因子是0.75。
// 当HashMap的“阈值”(阈值=HashMap总的大小*加载因子) < “HashMap实际大小”时,
// 就需要将HashMap的容量翻倍。
// 所以,(c.size()/.75f) + 1 计算出来的正好是总的空间大小。
// 接下来,说明为什么是 16 。
// HashMap的总的大小,必须是2的指数倍。若创建HashMap时,指定的大小不是2的指数倍;
// HashMap的构造函数中也会重新计算,找出比“指定大小”大的最小的2的指数倍的数。
// 所以,这里指定为16是从性能考虑。避免重复计算。
map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));
// 将集合(c)中的全部元素添加到HashSet中
addAll(c);
}
3、指定HashSet初始容量和加载因子的构造函数
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<E,Object>(initialCapacity, loadFactor);
}
4、指定HashSet初始容量的构造函数
public HashSet(int initialCapacity) {
map = new HashMap<E,Object>(initialCapacity);
}
5、指定HashSet初始容量和加载因子的构造函数
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);
}
三、HashSet遍历方式
1、通过Iterator遍历HashSet
HashSet set = new HashSet();
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator);
}
2、通过for-each增强for循环遍历HashSet
HashSet set = new HashSet();
String[] arr = (String[])set.toArray(new String[0]);
for (String str:arr)
System.out.printf("for each : %s\n", str);
四、HashSet代码示例
package Test;
import java.util.HashSet;
import java.util.Iterator;
/**
* Created by LKL on 2017/2/19.
* HashSet常用API的使用。
*/
public class TestHashSet1 {
public static void main(String[] args) {
// HashSet常用API
testHashSetAPIs() ;
}
/*
* HashSet除了iterator()和add()之外的其它常用API
*/
private static void testHashSetAPIs() {
// 新建HashSet
HashSet set = new HashSet();
// 将元素添加到Set中
set.add("a");
set.add("b");
set.add("c");
set.add("d");
set.add("e");
// 打印HashSet的实际大小
System.out.printf("size : %d\n", set.size());
// 判断HashSet是否包含某个值
System.out.printf("HashSet contains a :%s\n", set.contains("a"));
System.out.printf("HashSet contains g :%s\n", set.contains("g"));
// 删除HashSet中的“e”
set.remove("e");
// 将Set转换为数组
String[] arr = (String[])set.toArray(new String[0]);
for (String str:arr)
System.out.printf("for each : %s\n", str);
// 新建一个包含b、c、f的HashSet
HashSet otherset = new HashSet();
otherset.add("b");
otherset.add("c");
otherset.add("f");
// 克隆一个removeset,内容和set一模一样
HashSet removeset = (HashSet)set.clone();
// 删除“removeset中,属于otherSet的元素”
removeset.removeAll(otherset);
// 打印removeset
System.out.printf("removeset : %s\n", removeset);
// 克隆一个retainset,内容和set一模一样
HashSet retainset = (HashSet)set.clone();
// 保留“retainset中,属于otherSet的元素”
retainset.retainAll(otherset);
// 打印retainset
System.out.printf("retainset : %s\n", retainset);
// 遍历HashSet
for(Iterator iterator = set.iterator();
iterator.hasNext(); )
System.out.printf("iterator : %s\n", iterator.next());
// 清空HashSet
set.clear();
// 输出HashSet是否为空
System.out.printf("%s\n", set.isEmpty()?"set is empty":"set is not empty");
}
}
运行结果如下:
size : 5
HashSet contains a :true
HashSet contains g :false
for each : a
for each : b
for each : c
for each : d
removeset : [a, d]
retainset : [b, c]
iterator : a
iterator : b
iterator : c
iterator : d
set is empty
文章只是作为自己的学习笔记,借鉴了网上的许多案例,如果觉得阔以的话,希望多交流,在此
谢过…