上一篇我们分析了HashMap的源码,底层就是一个可变长数组+单向链表实现的,这篇我们接着分析一下HashSet的源码。HashSet是Set接口的一种实现方式,前面我们已经说过了,Set接口继承自Collection接口,但是Set接口并没有扩展任何方法,只是要求实现类保证Set集合内没有重复元素。在上一篇中我们知道HashMap中的key是唯一的,它不是正好满足了Set接口的要求吗。实际上HashSet就是这么实现的,使用HashMap的key来当做Set集合的实现,我们来看源码:
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
{
// 保存着一个HashMap的实例
private transient HashMap<E,Object> map;
// map接口是key-value类型的,但是Set接口只需要key就够了,所以HashMap中所有的value都是下面这个默认值了。
private static final Object PRESENT = new Object();
// 无参构造方法,初始化map
public HashSet() {
map = new HashMap<>();
}
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c); // addAll() 方法在AbstractCollection中提供了默认实现,这就是继承抽象类的好处
}
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
public Iterator<E> iterator() {
return map.keySet().iterator();
}
public boolean isEmpty() {
return map.isEmpty();
}
public boolean contains(Object o) {
return map.containsKey(o);
}
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
public void clear() {
map.clear();
}
}
HashSet继承自AbstractSet类,AbstractSet提供了Set接口的默认实现,和AbstractCollection与Collection,AbstractList与List之间的关系是一样的。AbstractSet继承自AbstractCollection类。