Java入門記(五):容器關係的梳理(下)——Map

來源:互聯網
上載者:User

標籤:

注意:閱讀本文及相關源碼時,需要資料結構相關知識,包括:雜湊表、鏈表、紅/黑樹狀結構。

 

  Map是將鍵(key)映射到值(value)的對象。不同的映射不能包含相同的鍵;每個鍵最多隻能映射到一個值。是常見Map的介面和實現。與Collection相比,繼承關係簡單不少。

一、Map介面和AbstractMap抽象類別

  Map介面除了增加映射、根據key擷取value、判斷映射中的key或value是否存在、刪除映射的基本方法外,還包含了返回包含所有key的Set、包含所有value的collection的方法。由於key不能重複,返回的Collection自然具有Set的屬性,很適合用Set返回。而value則不行。

  與其他Collection介面不同,Map介面中有一個子介面:Entry。Entry代表了一個映射,包含了key和value兩部分,同時,一個Enry的key沒有提供修改方法,而value允許修改。需要說明的是,如果用一個可變對象作為Map的key,若變化後equals()與之前的行為不同,那麼映射的行為是不確定的(JDK1.6文檔)。

  對於抽象類別AbstractMap,大部分實現的方法藉助了將所有entry組成的set返回的抽象方法entrySet():size()、isEmpty()(使用size())、containsValue()、containsKey()、get()、clear()、keySet()、values()等。而remove()、removeAll()、retainAll()、clear()、toString()則藉助了抽象方法iterator()。

  values()傳回值value的是一個匿名內部類實現的AbstractCollection。value在第一次訪問時建立,在後續所有訪問中返回。雖然不進行元素的同步,其引用幾乎總是不變的,但傳回值的行為會隨著Map中的元素變化:

 

public Collection<V> values() {    if (values == null) {        values = new AbstractCollection<V>() {          public Iterator<V> iterator() {             return new Iterator<V>() {              private Iterator<Entry<K,V>> i = entrySet().iterator();              public boolean hasNext() {                  return i.hasNext();              }              public V next() {                  return i.next().getValue();              }              public void remove() {                  i.remove();              }            };            }          public int size() {             return AbstractMap.this.size();          }          public boolean contains(Object v) {              return AbstractMap.this.containsValue(v);           }        };    }    return values;}

 

  對於Map.Entry,AbstractMap中實現了兩個索引值對類型:SimpleEntry和SimpleImmutableEntry。後者與前者的區別是,不允許setValue(),調用該方法拋出UnsupportedOperationException異常。

二、HashMap/LinkedHashMap/WeakHashMap

   在Java入門記(四):容器關係的梳理(上)——Collection一文中提到,HashSet/LinkedHashSet的底層實際是HashMap/LinkedHashMap。HashMap和一般的散列表實現方式相同,用數組存放相同雜湊值的元素所組成隊列的首元素,隊列的元素是Entry,包括了key、value、hash值、next等屬性。尋找指定key時,先做雜湊,根據雜湊值找到數組中對應的隊列頭,遍曆隊列找出key及對應的value。

  由於HashMap允許null作為key,這個key沒辦法做雜湊值的計算,只能遍曆雜湊值數組,找到首元素的key為null的隊列。這個實現可以參考私人方法getForNullKey()。

  HashMap的key的雜湊值數組有一個容量限制:必須為2的冪次。即使在建立HashMap時或調用resize()時指定一個非2的冪次的容量,實際調用時新的HashMap容量也會擴大到不小於這個指定容量的2的冪次的值。與之相關聯地,雜湊值的計算hash()和某個hash值在數組的索引的計算indexFor()方式為:

static int hash(int h) {        // This function ensures that hashCodes that differ only by        // constant multiples at each bit position have a bounded        // number of collisions (approximately 8 at default load factor).        h ^= (h >>> 20) ^ (h >>> 12);        return h ^ (h >>> 7) ^ (h >>> 4);}
static int indexFor(int h, int length) {    return h & (length-1);}

2的冪次可以保證計算索引時適當的截斷(捨棄高位)。

   LinkedHashMap與HashMap的關係並不像LinkedList和ArrayList那樣。從結構上來看,LinkedHashMap僅僅是把所有的Entry組成了一個雙向鏈表。這樣,在迭代遍曆時,可以使用插入順序或LRU順序訪問所有元素(通過設定accessOrder標記位)。

  WeakHashMap和HashMap很類似,其內部包含了一個ReferenceQueue,並且它的Entry是繼承自WeakReference的。通過這種方式,在clear()、resize()、size()、getTable()時,都會調用expungeStaleEntries()方法,記憶體回收掉不再使用的映射關係。這裡不介紹Reference的相關內容了。

  思考下上一篇文章所提出的問題:是不是可以先實現HashSet,再用HashSet實現HashMap?個人認為,這樣實現的HashSet中的元素(對應Map的Entry),只有鍵沒有值,是無法直接實現HashMap的。

二、Hashtable/Properties

  Hashtable雖然實現了Map介面,但沒有用AbstractMap來做。它的行為與HashMap很相似,保留下來是為了相容原來的代碼,不推薦繼續使用。

  繼承了Hashtable<Object,Object>的Properties稍有點不同,它與流的關係密切些,可儲存在流中或從流中載入。另外,它是安全執行緒的。

三、SortedMap和TreeMap

  SortedMap中的所有元素都是排過序的。這個“排序”不同於LinkedHashMap中將所有元素組織成一個鏈表,而是指任意任意兩個元素都可以比較大小關係,並根據這個比較規則Comparator進行排序。更準確的說,是鍵的大小關係。建立在有序的基礎上,SortedMap介面中包含了返回部分Map的方法subMap(K fromKey, K toKey)、headMap(K toKey)、tailMap(K fromKey)以及首尾key的方法firstKey()、lastKey()。

  TreeMap是SortedMap的一個實現,其Compartor可以為null,這種情況下比較元素大小時調用元素自身的compareTo()方法。

  TreeMap實際上使用了紅/黑樹狀結構,儲存了樹的根。關於紅/黑樹狀結構的演算法,講起來可以單獨開一篇文章,這裡不展開了,想瞭解的讀者可以讀下《演算法導論》的相關章節。TreeMap的元素插入、刪除其實是紅/黑樹狀結構節點的插入和刪除。在元素有序的前提下,找到特定的key(以及對應的value)同樣是使用了紅/黑樹狀結構的尋找方法。

Java入門記(五):容器關係的梳理(下)——Map

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.