TreeSet和TreeMap部分源码解析

Posted blogofjzq

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TreeSet和TreeMap部分源码解析相关的知识,希望对你有一定的参考价值。

首先我们看TreeSet的成员变量

private transient NavigableMap<E,Object> m;
private static final Object PRESENT = new Object();

第一行的NavigebleMap接口它的实现有TreeMap

第二行的Prensent马上就能知道它的作用了

然后我们看它的构造函数

TreeSet(NavigableMap<E,Object> m) {
        this.m = m;
    }
public TreeSet() {
        this(new TreeMap<E,Object>());
    }
public TreeSet(Comparator<? super E> comparator) {
        this(new TreeMap<>(comparator));
    }
public TreeSet(Collection<? extends E> c) {
        this();
        addAll(c);
    }
 public TreeSet(SortedSet<E> s) {
        this(s.comparator());
        addAll(s);
    }

我们能发现所有构造函数都是在初始化m,也就是NavigableMap

接下来看几个它的函数

public boolean add(E e) {
        return m.put(e, PRESENT)==null;
    }
public boolean contains(Object o) {
        return m.containsKey(o);
    }
public Iterator<E> iterator() {
        return m.navigableKeySet().iterator();
    }

到此我们可以发现TreeSet是基于TreeMap实现的,它利用了Map的Key唯一,保证TreeSet的值唯一,即TreeSet的值被put到TreeMap的key上,而value是一个相同的Object

 

知道了这一点,接下来我们开始进入TreeMap

还是先看它的成员变量

private final Comparator<? super K> comparator; //说明Key必须实现Comparator
private transient Entry<K,V> root;//TreeMap是一颗红黑树,这是根结点
private transient int size = 0;//大小
private transient int modCount = 0;//操作次数

接下来看它的构造函数

public TreeMap() {
        comparator = null;
    }
public TreeMap(Comparator<? super K> comparator) {
        this.comparator = comparator;
    }
public TreeMap(Map<? extends K, ? extends V> m) {
        comparator = null;
        putAll(m);
    }
public TreeMap(SortedMap<K, ? extends V> m) {
        comparator = m.comparator();
        try {
            buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
        } catch (java.io.IOException cannotHappen) {
        } catch (ClassNotFoundException cannotHappen) {
        }
    }

我们看到它的构造函数基本是在对comparator操作,和根据已有的结构添加为TreeMap(暂时忽略)

然后我们看我们最常用的 put()

public V put(K key, V value) {
        Entry<K,V> t = root;
        if (t == null) {
            compare(key, key); // type (and possibly null) check

            root = new Entry<>(key, value, null);
            size = 1;
            modCount++;
            return null;
        }
=============================================
        int cmp;
        Entry<K,V> parent;
        // split comparator and comparable paths
        Comparator<? super K> cpr = comparator;
        if (cpr != null) {
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
=================================================
else { if (key == null) throw new NullPointerException(); @SuppressWarnings("unchecked") Comparable<? super K> k = (Comparable<? super K>) key; do { parent = t; cmp = k.compareTo(t.key); if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else return t.setValue(value); } while (t != null); } Entry<K,V> e = new Entry<>(key, value, parent); if (cmp < 0) parent.left = e; else parent.right = e; fixAfterInsertion(e); size++; modCount++; return null; }

用等号把源码分成了上中下三部分,上面的因为此时Comparator为null,所以调用了Compare(key,key)

final int compare(Object k1, Object k2) {
        return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2)
            : comparator.compare((K)k1, (K)k2);
    }

中间的部分明显看出就是根据已有的Comparator进行比较,和在树上添加新的值

下面的部分有一句

Comparable<? super K> k = (Comparable<? super K>) key;

可以看出直接用了key的Comparator

 

至此告一段落,做一个小总结

TreeSet基于TreeMap实现,TreeMap底层是一个红黑树结构,TreeSet的值必须实现Comparator接口,TreeMap的key必须实现Comparator接口,他们根据Comparator决定每个值的位置

 


以上是关于TreeSet和TreeMap部分源码解析的主要内容,如果未能解决你的问题,请参考以下文章

Java - TreeSet源码解析

源码分析TreeMap和TreeSet

TreeSet源码解析笔记

java中treemap和treeset实现(红黑树)

集合之TreeSet(含JDK1.8源码分析)

Java 集合系列12之 TreeMap详细介绍(源码解析)和使用示例