TreeMap就這麼簡單【原始碼剖析】

Java3y發表於2018-04-12

前言

宣告,本文用得是jdk1.8

前面章節回顧:

本篇主要講解TreeMap~

看這篇文章之前最好是有點資料結構的基礎:

當然了,如果講得有錯的地方還請大家多多包涵並不吝在評論去指正~

一、TreeMap剖析

按照慣例,我簡單翻譯了一下頂部的註釋(我英文水平渣,如果有錯的地方請多多包涵~歡迎在評論區下指正)

TreeMap就這麼簡單【原始碼剖析】

接著我們來看看類繼承圖:

TreeMap就這麼簡單【原始碼剖析】

在註釋中提到的要點,我來總結一下:

  • TreeMap實現了NavigableMap介面,而NavigableMap介面繼承著SortedMap介面,致使我們的TreeMap是有序的
  • TreeMap底層是紅黑樹,它方法的時間複雜度都不會太高:log(n)~
  • 非同步
  • 使用Comparator或者Comparable來比較key是否相等與排序的問題~

對我而言,Comparator和Comparable我都忘得差不多了~~~下面就開始看TreeMap的原始碼來看看它是怎麼實現的,並且回顧一下Comparator和Comparable的用法吧!

1.1TreeMap的域

TreeMap就這麼簡單【原始碼剖析】

1.2TreeMap構造方法

TreeMap的構造方法有4個:

TreeMap就這麼簡單【原始碼剖析】

可以發現,TreeMap的構造方法大多數與comparator有關:

TreeMap就這麼簡單【原始碼剖析】

也就是頂部註釋說的:TreeMap有序是通過Comparator來進行比較的,如果comparator為null,那麼就使用自然順序~

打個比方:

  • 如果value是整數,自然順序指的就是我們平常排序的順序(1,2,3,4,5..)~

    TreeMap<Integer, Integer> treeMap = new TreeMap<>();

    treeMap.put(1, 5);
    treeMap.put(2, 4);
    treeMap.put(3, 3);
    treeMap.put(4, 2);
    treeMap.put(5, 1);

    for (Entry<Integer, Integer> entry : treeMap.entrySet()) {

        String s = entry.getKey() +"關注公眾號:Java3y---->" + entry.getValue();

        System.out.println(s);
    }
複製程式碼

TreeMap就這麼簡單【原始碼剖析】

1.3put方法

我們來看看TreeMap的核心put方法,閱讀它就可以獲取不少關於TreeMap特性的東西了~

TreeMap就這麼簡單【原始碼剖析】

下面是compare(Object k1, Object k2)方法


    /**
     * Compares two keys using the correct comparison method for this TreeMap.
     */
    @SuppressWarnings("unchecked")
    final int compare(Object k1, Object k2) {
        return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2)
            : comparator.compare((K)k1, (K)k2);
    }
複製程式碼

如果我們設定key為null,會丟擲異常的,就不執行下面的程式碼了。

TreeMap就這麼簡單【原始碼剖析】

1.4get方法

接下來我們來看看get方法的實現:

TreeMap就這麼簡單【原始碼剖析】

點進去getEntry()看看實現:

TreeMap就這麼簡單【原始碼剖析】

如果Comparator不為null,接下來我們進去看看getEntryUsingComparator(Object key),是怎麼實現的

TreeMap就這麼簡單【原始碼剖析】

1.5remove方法

TreeMap就這麼簡單【原始碼剖析】

刪除節點的時候呼叫的是deleteEntry(Entry<K,V> p)方法,這個方法主要是刪除節點並且平衡紅黑樹

平衡紅黑樹的程式碼是比較複雜的,我就不說了,你們去看吧(反正我看不懂)....

1.6遍歷方法

在看原始碼的時候可能不知道哪個是核心的遍歷方法,因為Iterator有非常非常多~

TreeMap就這麼簡單【原始碼剖析】

此時,我們只需要debug一下看看,跟下去就好!

TreeMap就這麼簡單【原始碼剖析】

TreeMap就這麼簡單【原始碼剖析】

於是乎,我們可以找到:TreeMap遍歷是使用EntryIterator這個內部類的

首先來看看EntryIterator的類結構圖吧:

TreeMap就這麼簡單【原始碼剖析】

可以發現,EntryIterator大多的實現都是在父類中:

TreeMap就這麼簡單【原始碼剖析】

那接下來我們去看看PrivateEntryIterator比較重要的方法:

TreeMap就這麼簡單【原始碼剖析】

我們進去successor(e)方法看看實現:

successor 其實就是一個結點的 下一個結點,所謂 下一個,是按次序排序後的下一個結點。從程式碼中可以看出,如果右子樹不為空,就返回右子樹中最小結點。如果右子樹為空,就要向上回溯了。在這種情況下,t 是以其為根的樹的最後一個結點。如果它是其父結點的左孩子,那麼父結點就是它的下一個結點,否則,t 就是以其父結點為根的樹的最後一個結點,需要再次向上回溯。一直到 ch 是 p 的左孩子為止。

來源:blog.csdn.net/on_1y/artic…

TreeMap就這麼簡單【原始碼剖析】

二、總結

TreeMap底層是紅黑樹,能夠實現該Map集合有序~

如果在構造方法中傳遞了Comparator物件,那麼就會以Comparator物件的方法進行比較。否則,則使用Comparable的compareTo(T o)方法來比較。

  • 值得說明的是:如果使用的是compareTo(T o)方法來比較,key一定是不能為null,並且得實現了Comparable介面的。
  • 即使是傳入了Comparator物件,不用compareTo(T o)方法來比較,key也是不能為null的

    public static void main(String[] args) {
        TreeMap<Student, String> map = new TreeMap<Student, String>((o1, o2) -> {
            //主要條件
            int num = o1.getAge() - o2.getAge();

            //次要條件
            int num2 = num == 0 ? o1.getName().compareTo(o2.getName()) : num;

            return num2;
        });

        //建立學生物件
        Student s1 = new Student("潘安", 30);
        Student s2 = new Student("柳下惠", 35);

        //新增元素進集合
        map.put(s1, "宋朝");
        map.put(s2, "元朝");
        map.put(null, "漢朝");

        //獲取key集合
        Set<Student> set = map.keySet();

        //遍歷key集合
        for (Student student : set) {
            String value = map.get(student);
            System.out.println(student + "---------" + value);
        }
    }
複製程式碼

TreeMap就這麼簡單【原始碼剖析】

我們從原始碼中的很多地方中發現:Comparator和Comparable出現的頻率是很高的,因為TreeMap實現有序要麼就是外界傳遞進來Comparator物件,要麼就使用預設key的Comparable介面(實現自然排序)

最後我就來總結一下TreeMap要點吧:

  1. 由於底層是紅黑樹,那麼時間複雜度可以保證為log(n)
  2. key不能為null,為null為丟擲NullPointException的
  3. 想要自定義比較,在構造方法中傳入Comparator物件,否則使用key的自然排序來進行比較
  4. TreeMap非同步的,想要同步可以使用Collections來進行封裝

參考資料:


TreeMap就這麼簡單【原始碼剖析】

明天要是無意外的話,可能會寫ConcurrentHashMap集合,敬請期待哦~~~~

文章的目錄導航zhongfucheng.bitcron.com/post/shou-j…

如果文章有錯的地方歡迎指正,大家互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同學,可以關注微信公眾號:Java3y。謝謝支援了!希望能多介紹給其他有需要的朋友

相關文章