目录
注:阅读本文之前,需要对HashMap有一定基础,移步此文 HashMap底层源码 细致解读
一、概述
HashSet
是实现Set
接口,底层数据结构是哈希表HashMap
,它保存的元素都是非重复的元素,但是不保证迭代的顺序。
对于HashSet
而言,它是基于HashMap
实现,所有元素都存放在HashMap
的Key
中,这也是为什么HashSet
没有重复元素的原因。
因为HashSet
底层使用HashMap
来保存所有元素,相关HashSet
的的操作基本上都是调用HashMap
的相关方法直接完成,因此HashSet
的实现比较简单,相关源代码也比较简单比较少。
总结HashSet特点:
- 底层数据结构是基于
HashMap
实现的 - 集合里面是没有重复元素的
- 线程不安全
- 允许使用
null
作为元素
二、源码解读
注:不同jdk版本的源码会有一定差异,不过大致上是相同的,我使用的是 openjdk version “1.8.0_342”。
类图
成员变量
// HashMap用于存储操作,HashSet底层封装类对象
private transient HashMap<E,Object> map;
// HashSet是将元素存放在HashMap的key中,因此使用一个静态常量来充当HashMap的value值
private static final Object PRESENT = new Object();
构造方法
构造方法1:public HashSet()
创建一个空的HashMap,一个空HashMap的默认容量是16,装载因子是0.75
public HashSet() {
map = new HashMap<>();
}
构造方法2:public HashSet(Collection<? extends E> c)
创建一个包含集合c
中所有不重复元素的HashSet
集合
public HashSet(Collection<? extends E> c) {
// 创建一个HashMap,如果c集合容量小于16,则初始容量为16;如果容量大于16,则传入集合c的容量
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
// 将集合c中的元素添加进HashMap,后文详解此addAll()方法
addAll(c);
}
构造方法3:public HashSet(int initialCapacity, float loadFactor)
创建一个具有指定容量和负载因子的HashMap
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
构造方法4:public HashSet(int initialCapacity)
创建一个具有指定容量的HashMap
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
构造方法5:HashSet(int initialCapacity, float loadFactor, boolean dummy)
创建一个具有指定容量和负载因子的LinkedHashMap
,这个包私有构造函数只被LinkedHashSet
使用
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
常用方法
// 返回集合中元素的个数
public int size() {
return map.size();
}
// 返回集合是否为空
public boolean isEmpty() {
return map.isEmpty();
}
// 返回集合中是否包含指定元素o
public boolean contains(Object o) {
return map.containsKey(o);
}
// 添加指定元素e
// 将e作为HashMap的key 常量PRESENT作为所有元素的value
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
// 移出指定元素o
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
// 清空集合中所有元素
public void clear() {
map.clear();
}
三、总结
总的来说,HashSet的底层源码非常简单,学懂HashMap即可掌握HashSet。