3.13 JDK源码阅读之TreeSet

 从图中可以看出:
(01) TreeSet继承于AbstractSet,并且实现了NavigableSet接口。
(02) TreeSet的本质是一个"有序的,并且没有重复元素"的集合,它是通过TreeMap实现的。TreeSet中含有一个"NavigableMap类型的成员变量"m,而m实际上是"TreeMap的实例"。

public class TreeSet<E> extends AbstractSet<E>
    implements NavigableSet<E>, Cloneable, java.io.Serializable
{

    // 使用NavigableMap的key来保存Set集合的元素
    private transient NavigableMap<E,Object> m;
    // 使用一个PRESENT作为Map集合的所有value
    private static final Object PRESENT = new Object();

    // 包访问权限的构造器,以指定的NavigableMap对象创建Set集合
    TreeSet(NavigableMap<E,Object> m) {
        this.m = m;马士兵
    }


    public TreeSet() {                                  // ①
        // 以自然顺序方式创建一个新的TreeMap,根据该TreeSet创建一个TreeSet
    this(new TreeMap<E,Object>());
    }

    public TreeSet(Comparator<? super E> comparator) {  // ②
        // 以定制顺序方式创建一个新的TreeMap,根据该TreeSet创建一个TreeSet
    // 使用该TreeMap的key来保存Set集合的元素
    this(new TreeMap<E,Object>(comparator));
    }

    public TreeSet(Collection<? extends E> c) {
        // 调用①号构造器创建一个TreeSet,底层以TreeMap保存集合元素
        this();
    // 向TreeSet中添加Collection集合c里的所有元素
        addAll(c);
    }

    public TreeSet(SortedSet<E> s) {
        // 调用②号构造器创建衣蛾TreeSet,底层以TreeMap保存集合元素
        this(s.comparator());
    // 向TreeSet中添加SortedSet集合s里的所有元素
    addAll(s);
    }

    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) {
        // 把c集合强制转换为SortedSet集合
            SortedSet<? extends E> set = (SortedSet<? extends E>) c;
        // 把m集合强制转换为TreeMap集合
            TreeMap<E,Object> map = (TreeMap<E, Object>) m;
            Comparator<? super E> cc = (Comparator<? super E>) set.comparator();
            Comparator<? super E> mc = map.comparator();
            // 如果cc和mc两个Comparator相等
            if (cc==mc || (cc != null && cc.equals(mc))) {
            // 把Collection中所有元素添加成TreeMap集合的key
                map.addAllForTreeSet(set, PRESENT);
                return true;
            }
        }
    // 直接调用父类的addAll()方法来实现
        return super.addAll(c);
    }
}

 与HashSet完全类似的是,TreeSet里绝大部分方法都是直接调用TreeMap的方法来实现的。

TreeSet中的重要方法

public boolean add(E e) {
        return m.put(e, PRESENT)==null;
    }
 
 public boolean remove(Object o) {
        return m.remove(o)==PRESENT;
    }
 
public void clear() {
        m.clear();
    }
 
 public boolean contains(Object o) {
        return m.containsKey(o);
    }
 
 public E first() {
        return m.firstKey();
    }
 
 public E last() {
        return m.lastKey();
    }

 可以看到TreeSet中与TreeMap中同名的方法全部都是调用的TreeMap中的方法来实现的,其中add方法在调用TreeMap的put方法时第二个参数传入的是固定值PRESENT,一个Object类型对象。

 总结

1TreeSet底层是基于TreeMap的(而TreeMap是基于红黑树的),但是仅仅用来保存Key,而不保存Value,因为TreeSet的add()方法在调用TreeMap的put方法的时候第二个参数传入的都是PRESENT这个固定的Object对象。
2可以看到TreeSet中的add与remove等方法均无synchronized关键字修饰,即TreeSet不是线程安全的,如果要使用同步的TreeSet需要使用Collections集合类的静态方法,即Set s=Collections.synchronizedSet(new TreeSet());
3TreeSet中的元素是自动排好序的,插入的值不允许为null。

4TreeSet中元素的值必须是唯一的,因为TreeSet底层是基于TreeMap的,而TreeMap不允许元素key重复。

猜你喜欢

转载自blog.csdn.net/weixin_41395565/article/details/81810866