一、HashSet底层实现
从HashSet的源码中可以发现,它的底层维护了一个HashMap,在new HashSet的时候,构造方法中其实是new了一个HashMap。
private transient HashMap<E,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);
}
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
在HashSet的方法中,底层基本都是直接调用的HashMap的方法。
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
/**
* Removes the specified element from this set if it is present.
* More formally, removes an element <tt>e</tt> such that
* <tt>(o==null ? e==null : o.equals(e))</tt>,
* if this set contains such an element. Returns <tt>true</tt> if
* this set contained the element (or equivalently, if this set
* changed as a result of the call). (This set will not contain the
* element once the call returns.)
*
* @param o object to be removed from this set, if present
* @return <tt>true</tt> if the set contained the specified element
*/
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
/**
* Removes all of the elements from this set.
* The set will be empty after this call returns.
*/
public void clear() {
map.clear();
}
所以HashSet的性质基本和HashMap无异,理解了HashMap的底层实现后,HashSet自然也就理解了。
HashMap请参考之前的文章-java集合之HashMap理解和分析
二、HashSet的其他性质
在HashMap中有一个性质,同一个HashMap中key只能有一个,不能重复,可以有一个null值。而在HashSet中,add方法的实现是用HashMap的key作为HashSet的value存储的,而底层HashMap的value全都是同一个静态值,在HashSet中,这个value(PRESENT)并没有任何作用。所以HashSet中的值也不能重复,且仅可以有一个null值。
private static final Object PRESENT = new Object();
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
在HashMap的分析中知道HashMap是线程不安全的,HashSet的底层使用HashMap实现的,并且HashSet的方法也没有做同步处理,所以HashSet和HashMap一样是线程不安全的。