Set源码解析

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) {
	   }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值