TreeSet源码分析

257 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第20天,点击查看活动详情

TreeSet 源码分析-TreeMap复用

TreeSet 大致的结构和 HashSet 相似,底层组合的是 TreeMap,所以继承了 TreeMap key 能够排序的功能,迭代的时候,也可以按照 key 的排序顺序进行迭代。

TreeSet 的 add 方法源码:

public boolean add(E e) {
    return m.put(e, PRESENT)==null;
}

可以看到,底层直接使用的是 HashMap 的 put 方法。

迭代 TreeSet 中的元素的源代码:

public Iterator<E> descendingIterator() {
    return m.keySet().iterator();
}

迭代 TreeSet 中的元素,那应该也是像 add 那样,直接使用 HashMap 已有的迭代能力

这种是思路一的实现方式,TreeSet 组合 TreeMap,直接选择 TreeMap 的底层能力进行包装,但 TreeSet 实际执行的思路却完全相反,我们看源码:

public interface NavigableSet<E> extends SortedSet<E> {
    Iterator<E> iterator();
    E lower(E e);
}  

NavigableSet 接口定义了迭代的一些规范,和一些取值的特殊方法。TreeSet 实现了该方法表示 TreeSet 本身已经定义了迭代的规范

public Iterator<E> iterator() {
    return m.navigableKeySet().iterator();
}

TreeSet 中定义了接口的规范,而TreeMap 负责去实现。

TreeSet排序

TreeSet中有自然排序和比较器排序两种,其中:

  1. 自然排序:TreeSet的add()方法会把存储的对象转型为Comparable类型,然后调用对象的compareTo()方法和集合中的对象比较。根据compareTo()方法返回的结果进行存储。
  2. 比较器排序:创建TreeSet的时候指定Comparator,如果传入了Comparator的子类实现对象,TreeSet内部就会自动调用compare()方法排序。

添加元素

    public  boolean addAll(Collection<? extends E> c) {
        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);
    }

if (m.size()==0 && c.size() > 0 && c instanceof SortedSet && m instanceof TreeMap) 判断当前集合有没有元素且当前集合是否属于TreeSet、插入的集合是否属于SortedSet 集合

SortedSet<? extends E> set = (SortedSet<? extends E>) c; 定义一个SortedSet类型的变量set,将集合c进行强制类型转换

TreeMap<E,Object> map = (TreeMap<E, Object>) m; 定义一个TreeMap类型的变量map,将集合m进行强制类型转换

Comparator<?> cc = set.comparator(); Comparator<? super E> mc = map.comparator(); 定义两个Comparator类型的变量,分别将c和m的构造器存储到这两个变量中

if (cc==mc || (cc != null && cc.equals(mc)))判断两个构造器地址是否相等

return super.addAll(c); 调用父类的addAll方法

总结

TreeSet 组合 TreeMap 实现的两种思路:

  1. TreeSet 直接使用 TreeMap 的某些功能,包装成新的 api。
  2. TreeSet 定义自己的 api和接口规范,而让 TreeMap 去实现。