SortedMap和TreeMap

1.接口SortedMap<K,V>

public interface SortedMap<K,V>
extends Map<K,V>
 保證按照鍵的升序(或降序)排列的映射,可以按照鍵的自然順序(按照 Comparable 接口的實現類中的定義來排序,其中只有一個方法compareTo())進行排序, 或者通過創建有序映射時提供的比較器(通過Comparator對象)進行排序。對有序映射的集合視圖

 (由 entrySet、keySet 和 values 方法返回)進行迭代時,此順序就會反映出來。


 要採用此排序,還需要提供一些其他操作(此接口是相似於 SortedSet 接口的映射)。

 插入有序映射的所有鍵都必須實現 Comparable 接口(或者被指定的比較器所接受,即在Comparator進行鍵的大小比較時,不會產生ClassCastException)。


 另外,所有這些鍵都必須是可互相比較的:k1.compareTo(k2)(或 comparator.compare(k1, k2))
 對有序映射中的任意兩個元素 k1 和 k2 都不得拋出 ClassCastException。

 試圖違反這些限制將導致違反方法或者構造方法的調用,從而拋出 ClassCastException。


 注意,如果有序映射(SortedMap)正確實現了 Map 接口,則有序映射所保持的順序(無論是否明確提供了比較器)都必須保持相等一致性。

 (相等一致性 的精確定義請參閱 Comparable 接口或 Comparator 接口,相等一致性即判斷相等的方式與返回值是相同的,相等都是返回0,大於或小於分別返回1和-1)。 這也是因爲 Map 接口是按照 equals 操作定義的,但有序映射使用它的 compareTo(或 compare)方法對所有鍵進行比較,

 因此有序映射的觀點來看,此方法認爲兩個對象擁有相等的映射鍵則說明它們是相等的


 即使順序沒有保持相等一致性,樹映射的行爲仍然是 定義良好的,只不過沒有遵守 Map 接口的常規協定。
 所有通用有序映射實現類(TreeMap是SortedMap的自帶的唯一實現類,因此以TreeMap爲例)都應該提供 4 個“標準”構造方法:

 1) void(不帶參數)構造方法,創建空的有序映射,按照鍵的自然順序 排序。

public TreeMap() {
        comparator = null;
}


//TreeMap自身沒有定義比較器comparator且沒有實現Comparable,因此按照鍵的自然順序排序,鍵的自然順序是什麼?即鍵所屬的類應該實現了Comparable接口,否則無法實現排序

 2) 帶有一個 Comparator 類型參數的構造方法,創建一個空的有序映射,根據指定的比較器排序。

    public TreeMap(Comparator<? super K> comparator) {
        this.comparator = comparator;
    }


//TreeMap指定了一個Comparator對象作爲自身的比較器,其中的compare()會對TreeMap中的鍵進行比較

 3) 帶有一個 Map 類型參數的構造方法,創建一個鍵-值映射關係與參數相同的有序映射,按照鍵的自然順序排序。

    public TreeMap(Map<? extends K, ? extends V> m) {
        comparator = null;
        putAll(m);
    }


//將一個普通的Map實現類對象(沒有按鍵排序),進行鍵的自然順序的排序,以鍵所屬類中實現的compareTo()爲排序依舊(Comparable接口的實現)

 4) 帶有一個有序映射類型參數的構造方法,創建一個新的有序映射,鍵-值映射關係及排序方法與輸入的有序映射相同。如TreeMap(SortedMap<K,? extends V> 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) {
        }
    }

//上述直接傳入了一個SortedMap的實現類對象m,那麼m中一定實現了某種排序方式,所以將m中的Comparator對象賦給自身的Comparator對象,鍵值對直接複製就可以。

 除了 JDK 實現(TreeMap 類)遵循此建議外,無法保證強制實施此建議(因爲接口不能包含構造方法)。

2.TreeMap<K,V>

 TreeMapSortedMap接口的基於紅黑樹的實現。此類保證了映射按照升序順序排列關鍵字, 根據使用的構造方法不同,可能會按照鍵的類的自然順序進行排序(參見 Comparable), 或者按照創建時所提供的比較器進行排序。
 此實現爲 containsKey、get、put 和 remove 操作提供了保證的 log(n) 時間開銷。
 這些算法是 Cormen、Leiserson 和 Rivest 的《Introduction to Algorithms》中的算法的改編。
 注意,如果有序映射要正確實現 Map 接口,則有序映射所保持的順序(無論是否明確提供比較器)都必須保持與等號一致。
(請參見與等號一致 的精確定義的 Comparable 或 Comparator。)這也是因爲 Map 接口是按照等號操作定義的,
 但映射使用它的 compareTo(或 compare)方法對所有鍵進行比較,因此從有序映射的觀點來看,
 此方法認爲相等的兩個鍵就是相等的。即使順序與等號不一致,有序映射的行爲仍然是 定義良好的;
 只不過沒有遵守 Map 接口的常規約定。
 注意,此實現不是同步的。如果多個線程同時訪問一個映射,並且其中至少一個線程從結構上修改了該映射,
 則其必須 保持外部同步。(結構上修改是指添加或刪除一個或多個映射關係的操作;
 僅改變與現有鍵關聯的值不是結構上的修改。)這一般通過對自然封裝該映射的某個對象進行同步操作來完成。
 如果不存在這樣的對象,則應該使用 Collections.synchronizedMap 方法來“包裝”該映射。
 最好在創建時完成這一操作,以防止對映射進行意外的不同步訪問,如下所示:
     Map m = Collections.synchronizedMap(new TreeMap(...));
 由所有此類的“collection 視圖方法”所返回的迭代器都是快速失敗的:在迭代器創建之後,
 如果從結構上對映射進行修改,除非通過迭代器自身的 remove 或 add 方法,其他任何時間任何方式的修改,
 迭代器都將拋出 ConcurrentModificationException。因此,面對併發的修改,迭代器很快就完全失敗,
 而不是冒着在將來不確定的時間任意發生不確定行爲的風險。
 注意,迭代器的快速失敗行爲無法得到保證,因爲一般來說,不可能對是否出現不同步併發修改做出任何硬性保證。
 快速失敗迭代器會盡最大努力拋出 ConcurrentModificationException。
 因此,爲提高這類迭代器的正確性而編寫一個依賴於此異常的程序是錯誤的做法:迭代器的快速失敗行爲應該僅用於檢測 bug。
注意1:此實現不是同步的。不是線程安全的。
注意2:TreeMap是用鍵來進行升序順序來排序的。通過Comparable 或 Comparator來排序。
注意3:由所有此類的“collection 視圖方法”所返回的迭代器都是快速失敗的。
注意4:和HashMap一樣,如果插入重複的元素,後面的元素會覆蓋前面的。
注意5: 鍵不可以爲null,但是值可以爲null

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章