在分析HashSet源码前,先看看HashSet的继承关系api
从上图能够看出,HashSet继承自AbstractSet,实现了Set接口,接着看一下源码中的注释安全
到此发现,HashSet实际上能够拆分红Hash跟Set,Hash指的是HashMap,Set则是指实现了Set接口,这样看来,HashSet的实现其实就比较简单了,下面开始分析源码。bash
//序列化ID
static final long serialVersionUID = -5024744406713321676L;
//内置的HashMap
private transient HashMap<E,Object> map;
// 就是一个傀儡,填充HashMap的Value而已,没有实际意义
private static final Object PRESENT = new Object();复制代码
初始化一个空的HashMapui
public HashSet() {
map = new HashMap<>();
}复制代码
HashMap给定一个容量this
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}复制代码
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}复制代码
dummy做为Value是基本类型跟引用类型,注意此处初始化的是一个LinkedHashMapspa
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}复制代码
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}复制代码
调用addAll方法线程
public boolean addAll(Collection<? extends E> c) {
boolean modified = false;
//循环遍历
for (E e : c)
//若是set中没有此元素,添加成功
if (add(e))
modified = true;
return modified;
}复制代码
添加一个元素,若是Map中存在,返回false,不然返回truecode
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}复制代码
看一下Map的put方法cdn
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
if (key == null)
return putForNullKey(value);
int hash = sun.misc.Hashing.singleWordWangJenkinsHash(key);
int i = indexFor(hash, table.length);
for (HashMapEntry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
//这里比较了hash值跟equals方法
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}复制代码
因此Set元素必须复写hashcode跟equals方法,否则会致使元素错乱blog
public boolean remove(Object o) {
//直接调用map的方法
return map.remove(o)==PRESENT;
}复制代码
public void clear() {
//调用map的Clear方法
map.clear();
}复制代码
public boolean contains(Object o) {
调用map的contains方法
return map.containsKey(o);
}复制代码
public boolean isEmpty() {
//调用map的isEmpty方法
return map.isEmpty();
}复制代码
public Iterator<E> iterator() {
//由于不须要value,因此只是调用了keySet的iterator
return map.keySet().iterator();
}复制代码
分析了一下,其实最终的底层实现都是在调用HashMap的方法,因此了解了HashMap的源码以后,HashSet其实就会比较简单了