前言
HashSet实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。Set集合取出元素的方式只有一个,那就是迭代器。
Set接口中的方法与Collection接口中的方法相同。
- HashSet底层依赖于HashMap,关于HashMap源码详解见:HashMap源码详解
正文
HashSet的源码分析
1,类名及类成员变量
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable {
static final long serialVersionUID = -5024744406713321676L;
// 底层使用HashMap来组织元素
private transient HashMap<E,Object> map;
// PRESENT作为静态常量,用来填充HashMap的value
private static final Object PRESENT = new Object();
}
2,HashSet类构造方法
// 1,默认无参构造方法,构造一个空的HashSet,初始容量16,加载因子0.75
public HashSet() {
map = new HashMap<>();
}
// 2,构造指定容量的空HashSet
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
// 3,构造指定容量和加载因子的空HashSet
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
// 4,内部构造方法,不对外开放。对LinkedHashSet的支持
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
// 5,构造一个包含指定集合的HashSet
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
3,HashSet类常用方法
// add()调用map的put()方法,value用PRESENT常量填充
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
// size()调用map的size()方法
public int size() {
return map.size();
}
// iterator()调用map的迭代器方法
public Iterator<E> iterator() {
return map.keySet().iterator();
}
总结
HashSet完全依赖于HashMap,所以要好好理解HashMap的实现原理。