感兴趣的话大家可以关注一下公众号 : 猿人刘先生 , 欢迎大家一起学习 , 一起进步 , 一起来交流吧!
HashSet
HashSet类实现了由哈希表(实际上是HashMap实例)支持的Set接口 , 底层采用HashMap来保存的数据 , 存在HashSet中的元素是无序且不重复的并且HashSet是线程不安全的 , 这种不重复其实是由HashMap实现的 , 所以HashSet的实现也是相对比较简单的 , 对于它的操作其实都是调用HashMap的方法来实现的
HashSet类结构图
HashSet基本属性
// 保存数据的容器
private transient HashMap<E,Object> map;
// Dummy value to associate with an Object in the backing Map
// 存储在HashMap中的key对应的value值
private static final Object PRESENT = new Object();
HashSet构造方法
-
loadFactor: 负载因子 , 用来计算HashMap扩容时的阈值
-
initialCapacity : HashMap的容量
-
HashMap的阈值计算公式 : 阈值(threshold) = 扩容因子(loadFactor) * 容量(capacity)
-
如果扩容因子和容量都是默认的话 , 那么阈值就是 0.75f * 16 = 12
-
如果当HaspMap中table(也称为桶)的长度大于等于阈值时就会触发扩容机制
// HashSet默认无参构造方法 , 直接初始化一个Map
public HashSet() {
map = new HashMap<>();
}
// 使用默认负载因子计算出HashMap的初始容量 , 并且和16取最大值 , 然后将传入的集合添加到HashSet的构造器
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
// 使用指定的容量和负载因子进行HashMap的初始化
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
// 使用指定的容量进行HashMap的初始化
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
// 初始化一个只能由 LinkedHashSet使用的HashSet集合 , 并且指定负载因子和初始容量
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
// 将一个集合的元素添加到HashMap中
public boolean addAll(Collection<? extends E> c) {
boolean modified = false;
for (E e : c)
if (add(e))
modified = true;
return modified;
}
HashSet常用方法
// HashSet的长度
public int size() {
return map.size();
}
// 如果此集合不包含任何元素,则返回true
public boolean isEmpty() {
return map.isEmpty();
}
// 如果此集合包含指定元素 , 则返回true
public boolean contains(Object o) {
return map.containsKey(o);
}
// 添加一个元素 , 如果元素不存在HashMap则调用HashMap的put()方法添加并返回true , 否则的话不进行任何操作并且直接返回false
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
// 移除一个元素 , 如果元素不存在HashMap则调用HashMap的remove()方法移出并返回true , 否则的话不进行任何操作并且直接返回false
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
// 从此集合中移除所有元素。此调用返回后,该集合将为空。
public void clear() {
map.clear();
}
总结
通过源码我们可以看出 , HashSet的底层通过HashMap来实现的 , 而HashMap在1.7之前使用的是数组+链表 , 在1.8之后使用的是数据+链表+红黑树实现 , 因为HashMap的无序 , 不可重复及线程不安全 , 所以HashSet也是如此 , 通常往HashSet中重复添加元素时并不会覆盖