【JDK1.8】JDK1.8集合源碼閱讀——TreeMap(一)


一、前言

在前面兩篇隨筆中,我們提到過,當HashMap的桶過大的時候,會自動將鏈表轉化成紅黑樹結構,當時一筆帶過,因為我們將留在本章中,針對TreeMap進行詳細的了解。


二、TreeMap的繼承關系

下面先讓我們來看一下TreeMap的繼承關系,對它有一個大致的了解:

TreeMap的繼承關系

可以看到,除了在之前HashMap里常見的繼承類和接口以外,TreeMap實現了NavigableMap接口,而NavigableMap繼承自SortedMap,由名字可以看出,只是一個用來實現排序的接口。而這也是為什么TreeMap能夠實現排序的原因。由於篇幅關系,將TreeMap的源碼解析分為三部分,本章將對接口NavigableMap以及SortedMap進行解析。


三、SortedMap接口源碼解析

3.1 SortedMap接口

public interface SortedMap<K,V> extends Map<K,V> {
  //返回用於對鍵的進行排序的比較器,如果此映射使用其鍵的自然排序,則為null
  Comparator<? super K> comparator();
  //返回從fromKey(包括)到toKey(不包括)之間的map
  SortedMap<K,V> subMap(K fromKey, K toKey);
  //返回小於toKey的map
  SortedMap<K,V> headMap(K toKey);
  //返回大於或等於fromKey的map
  SortedMap<K,V> tailMap(K fromKey);
  //返回map中第一個(最低)鍵
  K firstKey();
  //返回map中最后一個(最高)鍵
  K lastKey();
  Set<K> keySet();
  Collection<V> values();
  Set<Map.Entry<K, V>> entrySet();
}

SortedMap的接口比較簡單,沒有很特別的地方,唯一比較特別的就是返回Comparator這個接口,可以設想實現排序功能的秘密或許就藏在此處。下面讓我們來看一下Comparator和Comparable接口,兩者之間有點關聯,可以理解為Comparable自帶了比較功能,而Comparator是賦予沒有比較能力的對象一種比較能力。舉個簡單例子:面對一道計算題,小明天生口算能力很強,看一眼就能算出來答案。而小李沒有這種能力,需要借助計算器才能得出答案。


3.2 Comparable接口

先讓我們看下它的代碼:

public interface Comparable<T> {
  //如果小於o,返回負數;等於o,返回0;大於o返回正數。
  public int compareTo(T o);
}

對,就是這么簡單,里面傳入一個泛型T的對象o,對o進行比較。如果小於o,返回負數;等於o,返回0;大於o返回正數。

我們熟悉的很多對象如StringIntegerDouble等都實現了這個接口。可以來看一下簡單的例子:

public class Item implements Comparable<Item> {
  private String name;
  private int price;
  
  public Item(String name, int price) {
    this.name = name;
    this.price = price;
  }
  
  public int getPrice() {
    return price;
  }
  
  public String getName() {
    return name;
  }
  
  @Override
  public String toString() {
    return "Item{" +
      "name='" + name + '\'' +
      ", price=" + price +
      '}';
  }
  
  @Override
  public int compareTo(Item o) {
    if (this.name.compareTo(o.name) < 0) {
      return -1;
    } else if (this.name.compareTo(o.name) > 0) {
      return 1;
    } else {
      return 0;
    }
  }
  
  public static void main(String[] args) {
    List<Item> items = Arrays.asList(new Item("banana", 200), new Item("apple", 400));
    System.out.println("before:" + items);
    Collections.sort(items);
    System.out.println("after:" + items);
  }
}

上述main函數的輸出:

before:[Item{name='banana', price=200}, Item{name='apple', price=400}]
after:[Item{name='apple', price=400}, Item{name='banana', price=200}]

上面的例子中,我們自己實現了Comparable接口,比較了Item的name屬性,然后通過Collections.sort對它進行了排序(值得注意的是:沒有實現Comparable接口的對象不能使用該方法)。但是,如果我不想用name屬性對它進行排序,想對price進行排序呢,或者先對name排序,相同的話在對price進行排序呢,用這個不就沒法實現了嗎。這就需要提到了下面的Comparator接口


3.3 Comparator接口

照例先來看一下代碼:

@FunctionalInterface
public interface Comparator<T> {
  // 核心方法,用來比較兩個對象,如果o1小於o2,返回負數;等於o2,返回0;大於o2返回正數
  int compare(T o1, T o2);
  // 好像很少用到,一般都用對象自帶的equals
  boolean equals(Object obj);
  
  /**-----------下面的都是JDK1.8新增的接口,挑幾個放進去----------*/

  //返回反向排序比較器
  default Comparator<T> reversed() {
    return Collections.reverseOrder(this);
  }
  //根據名字知道,先進行compare比較后,再進行一次比較
  default Comparator<T> thenComparing(Comparator<? super T> other) {
    Objects.requireNonNull(other);
    return (Comparator<T> & Serializable) (c1, c2) -> {
      int res = compare(c1, c2);
      return (res != 0) ? res : other.compare(c1, c2);
    };
  }
  //對int類型的key進行比較
  public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor) {
    Objects.requireNonNull(keyExtractor);
    return (Comparator<T> & Serializable)
      (c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2));
  }
  //返回正常順序的比較器
  public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {
    return (Comparator<T>) Comparators.NaturalOrderComparator.INSTANCE;
  }
}

一起來看一下如何使用,先來看一下JDK1.8以前的用法:

public class SimpleComparator implements Comparator<Item> {
  @Override
  public int compare(Item o1, Item o2) {
    return o1.price - o2.price;
  }
  
  public static void main(String[] args) {
    List<Item> items = Arrays.asList(new Item("banana", 200), new Item("apple", 400), new Item("Orange", 100));
    Collections.sort(items, new SimpleComparator());
    System.out.println(items);
  }
}

上述main函數的輸出是:

[Item{name='Orange', price=100}, Item{name='banana', price=200}, Item{name='apple', price=400}]

JDK1.8以前的用法要自己手動實現Comparator接口,然后調用Collections.sort(),傳入實現類來完成排序,非常麻煩,而JDK1.8則相對來說簡單了很多:

public static void main(String[] args) {
  List<Item> items = Arrays.asList(new Item("banana", 200), new Item("apple", 400), new Item("Orange", 100));
  Collections.sort(items, (Item a, Item b) -> a.price - b.price);
  System.out.println(items);
}

甚至,我們可以不使用Collections.sort:

public static void main(String[] args) {
  List<Item> items = Arrays.asList(new Item("banana", 100), new Item("Orange", 100), new Item("apple", 400), new Item("Orange", 50));
  items.sort((Item a, Item b) -> a.price - b.price);
  System.out.println(items);
  //使用上面的thenComparing
  items.sort(Comparator.comparing(Item::getName).thenComparing(Comparator.comparingInt(Item::getPrice)));
  System.out.println("after using thenComparing: " + items); 
}

上述main函數的輸出:

 [Item{name='orange', price=50}, Item{name='banana', price=100}, Item{name='orange', price=100}, Item{name='apple', price=400}]
 after using thenComparing: [Item{name='apple', price=400}, Item{name='banana', price=100}, Item{name='orange', price=50}, Item{name='orange', price=100}]

四、NavigableMap接口源碼解析

public interface NavigableMap<K,V> extends SortedMap<K,V> {
  //返回鍵小於且最接近Key(不包含等於)的鍵值對,沒有返回null
  Map.Entry<K,V> lowerEntry(K key);
  //返回小於且最接近(不包含等於)Key的鍵,沒有返回null
  K lowerKey(K key);
  //返回鍵小於且最接近(包含等於)Key的鍵值對,沒有返回null
  Map.Entry<K,V> floorEntry(K key);
  //返回小於且最接近(包含等於)Key的鍵,沒有返回null
  K floorKey(K key);
  //返回大於且最接近(包含等於)給定key的鍵值對,沒有返回null
  Map.Entry<K,V> ceilingEntry(K key);
  //同上
  K ceilingKey(K key);
  //返回大於且最接近(不包含等於)給定key的鍵值對
  Map.Entry<K,V> higherEntry(K key);
  //同上
  K higherKey(K key);
  //返回第一個Entry
  Map.Entry<K,V> firstEntry();
  //返回最后一個Entry
  Map.Entry<K,V> lastEntry();
  //移除並返回第一個Entry
  Map.Entry<K,V> pollFirstEntry();
  //同上
  Map.Entry<K,V> pollLastEntry();
  //返回map中包含的映射關系的逆序視圖
  NavigableMap<K,V> descendingMap();
  //返回map中包含的鍵的NavigableSet視圖。 set的迭代器按key的升序
  NavigableSet<K> navigableKeySet();
  //逆序
  NavigableSet<K> descendingKeySet();
  //根據fromKey和toKey來返回子map,兩個boolean參數用於是否包含該key
  NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
                             K toKey,   boolean toInclusive);
  //返回小於(或等於,根據inclusive)toKey的map
  NavigableMap<K,V> headMap(K toKey, boolean inclusive);
  //返回大於(或等於,根據inclusive)fromKey的map
  NavigableMap<K,V> tailMap(K fromKey, boolean inclusive);
  SortedMap<K,V> subMap(K fromKey, K toKey);
  SortedMap<K,V> headMap(K toKey);
  SortedMap<K,V> tailMap(K fromKey);
}

注意:上述返回的map與原map是相互影響的。


五、總結

本章分析了TreeMap的繼承關系,給后面分析TreeMap作為鋪墊。SortedMap和NavigableMap的接口中,包含了大量的返回Map的方法,這也是作為排序Map的一大特點吧。最后謝謝各位園友觀看,與大家共同進步!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM