Set是日常开发中经常使用的一个数据结构,其元素不可重复。
无论是HashSet、LinkedHashSet还是TreeSet。它们的数据结构的本质都是对应的Map。
其内部有一个Map类型的成员变量map,HashSet的元素对应map的key值,对应的value值统一为一个空对象(PRESENT )
一、 主要的成员变量
//HashSet
private transient HashMap<E,Object> map;
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
//TreeSet
private transient NavigableMap<E,Object> m;
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
二、通过Map实现的方法
对Set的包括构造器、成员方法在内的操作都通过Map实现,以HashMap的无参构造器、add、remove、iterator为例。
public HashSet() {
map = new HashMap<>();
}
//元素原来不存在,返回true,否则false
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
//元素原来存在返回true,否则false
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
public Iterator<E> iterator() {
return map.keySet().iterator();
}
三. 从集合处继承的方法
1. Abstractollection#addAll
addAll将集合内的元素全部加入HashSet。
可以看到,遍历集合调用add方法实现,只要集合中有1个元素是HashSet中没有的,即返回true。
public boolean addAll(Collection<? extends E> c) {
boolean modified = false;
for (E e : c)
if (add(e))
modified = true;
return modified;
}
2. AbstractSet#removeAll
removeAll将所有集合中的元素从HashSet移除。
分两种情况以减少循环的长度。
(1)HashSet的容量大于集合容量,遍历集合,调用HashSet#remove方法移除元素。
(2)否则,通过迭代器遍历HashSet,如果元素在集合中,调用Iterator#remove移除元素。
同样的,只要集合中有1个元是HashSet中有的,即返回true。
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);
boolean modified = false;
if (size() > c.size()) {
for (Iterator<?> i = c.iterator(); i.hasNext(); )
modified |= remove(i.next());
} else {
for (Iterator<?> i = iterator(); i.hasNext(); ) {
if (c.contains(i.next())) {
i.remove();
modified = true;
}
}
}
return modified;
}
3. AbstractCollection#retainAll
retainAll返回HashSet和集合的交集。
通过迭代器遍历HashSet,如果元素在集合中不存在,则通过Iterator#remove进行移除元素。同样的,只要移除了一个元素,则返回true。
public boolean retainAll(Collection<?> c) {
Objects.requireNonNull(c);
boolean modified = false;
Iterator<E> it = iterator();
while (it.hasNext()) {
if (!c.contains(it.next())) {
it.remove();
modified = true;
}
}
return modified;
}
4. TreeSet#addAll
TreeSet对addAll进行了重写。
和TreeMap的构造器public TreeMap(SortedMap<K, ? extends V> m)
,针对集合为SortedSet且map为TreeMap的场景下,调用递归方法HashMap#buildFromSorted进行处理。
public boolean addAll(Collection<? extends E> c) {
// Use linear-time version if applicable
if (m.size()==0 && c.size() > 0 &&
c instanceof SortedSet &&
m instanceof TreeMap) {
SortedSet<? extends E> set = (SortedSet<? extends E>) c;
TreeMap<E,Object> map = (TreeMap<E, Object>) m;
Comparator<?> cc = set.comparator();
Comparator<? super E> mc = map.comparator();
if (cc==mc || (cc != null && cc.equals(mc))) {
map.addAllForTreeSet(set, PRESENT);
return true;
}
}
return super.addAll(c);
}
void addAllForTreeSet(SortedSet<? extends K> set, V defaultVal) {
try {
buildFromSorted(set.size(), set.iterator(), null, defaultVal);
} catch (java.io.IOException cannotHappen) {
} catch (ClassNotFoundException cannotHappen) {
}
}