1. 程式人生 > >TreeMap和TreeSet在排序時如何比較元素?Collections工具類中的sort()方法如何比較元素?

TreeMap和TreeSet在排序時如何比較元素?Collections工具類中的sort()方法如何比較元素?

TreeMap和TreeSet都是有序的集合。

TreeSet要求集合中的元素實現Comparable介面,並實現compareTo方法進行比較,如果compareTo方法實現的不好,可能會導致元素插入失敗,因為集合內部也通過compareTo方法來比較元素是否相等(而不是通過equals),即判斷一個元素是否可插入。

TreeMap要求鍵列的元素實現Comparable介面,與TreeSet對元素的要求一樣。

TreeSet其實內部是通過一個TreeMap來實現的,用了組合的設計模式。

我們來看下原始碼

/**
     * The backing map.
     */
    private transient NavigableMap<E,Object> m;

    // Dummy value to associate with an Object in the backing Map
    private static final Object PRESENT = new Object();

    public TreeSet() {
        this(new TreeMap<E,Object>());
    }
可以看到,在構造TreeSet時,也構造了一個TreeMap,並且Map中的value不使用。

我們呼叫TreeSet的add方法,其實是呼叫了TreeMap的put方法,我們再看一下原始碼。

    public boolean add(E e) {
        return m.put(e, PRESENT)==null;
    }
PRESENT是一個Object物件,沒有實際意義,現在我們進入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;
    }
我們可以看到,方法內是通過元素實現Comparable介面並實現了的compareTo方法來比較兩個key是否相等的。並且進行排序。

第二個問題:

Collections有兩個sort方法,可以僅僅傳入一個由實現了Comparable介面元素構成的List物件,當然也可以傳入集合中的元素沒有實現Comparable的List物件,但是要求傳入第二個引數,引數是Comparator介面的子型別(需要重寫compare方法實現元素的比較),相當於一個臨時定義的排序規則,其實就是通過介面注入比較元素大小的演算法,也是對回撥模式的應用(Java中對函數語言程式設計的支援)。

另外一點,

Collection和Collections有很大區別,Collection是是一個

集合介面。它提供了對集合物件進行基本操作的通用介面方法。Collection介面在Java 類庫中有很多具體的實現。Collection介面的意義是為各種具體的集合提供了最大化的統一操作方式。

而Collections是一個包裝類,包裝了許多操作集合的靜態方法。就相當於一個工具類。