一、HashSet
HashSet是基于HashMap实现的,他的方法比较简单,但是大部分方法都和HashMap有关。需要先了解HashMap在了解HashSet。关于HashMap在上一篇源码分析有介绍。
了解完HashMap再来看HashSet会发现其实HashSet会比较简单
二、源码分析
2.1 继承结构和分析
实现了Set接口,继承AbstractSet
2.2 HashSet属性
比较简单,不是很多
static final long serialVersionUID = -5024744406713321676L;
//存放数据的hashmap
private transient HashMap<E,Object> map;
// map中存放的value值,后面会有介绍
private static final Object PRESENT = new Object();
2.3 构造方法
构造方法有点多,来看下
2.3.1 无参构造方法
实例化了HashMap
public HashSet() {
map = new HashMap<>();
}
2.3.2 集合参数的构造方法
public HashSet(Collection<? extends E> c) {
//根据传入集合大小初始化hashMap实例的参数
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
//将集合加入map中
public boolean addAll(Collection<? extends E> c) {
boolean modified = false;
for (E e : c)
if (add(e))
modified = true;
return modified;
}
public boolean add(E e) {
//将PRESENT加入value,都使用同一个对象做值
return map.put(e, PRESENT)==null;
}
2.3.3 初始化容量和负载因子的构造参数
//根据传入参数构造hashmap
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
2.3.4 带初始化容量的构造参数
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
2.3.5 初始化容量、负载因子和布尔值的构造参数
初始化LinkedHashMap
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
可以看出构造方法都是和HashMap有关,即HashSet的实现和HashMap有很大联系,关于HashMap可以参见上一篇的解析
2.4 常用方法
2.4.1 增加
想HashMap中添加元素,PRESENT是一个对象,被static final修饰
public boolean add(E e) {
//如果不存在e,则返回null值,添加成功。如果存在e,则返回已经存在的PRESENT,在这里即判断为false
return map.put(e, PRESENT)==null;
}
2.4.2 删除
依旧是map的remove方法,返回value值,所有的value值都是PRESENT
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
2.4.3 查询
还是HashMap的方法,不多介绍
public boolean contains(Object o) {
return map.containsKey(o);
}
2.4.4 迭代器
因为只存了有用的key值,只生成key值的迭代器
public Iterator<E> iterator() {
return map.keySet().iterator();
}
三、总结
HashSet的底层实现是使用了HashMap,根据HashMap的特性,可以知道:
- 存储元素是无序的
- 只存储了key值是有用的,因此元素也是不能重复的
- 根据HashMap的key值可以存放null值可知,HashSet也是可以存放null值的