Java HashMap 分析之一:基本結構

來源:互聯網
上載者:User

Java的HashMap非常的常用,本篇研究它的實現演算法,最後希望計算出記憶體佔用,效能的量化資料,然後得出什麼時候使用HashMap,什麼時候不能濫用的結論。
HashMap實際上是一個數組,數組裡面的每個元素都是一個鏈表。每個元素在通過put方法放入HashMap中的時候,要按照如下步驟進行:
1.根據該元素自身提供的hashcode計算出散列值,該散列值就是數組的下標
2.將新元素放入該數組位置的鏈表中

先來看一下數組的定義:

 

[java] view plaincopyprint?

 
  1. /** 
  2.      * The table, resized as necessary. Length MUST Always be a power of two. 
  3.      */  
  4.     transient Entry[] table;  


這是一個數組,transient關鍵字告訴我們它不會參與序列化。既然是一個數組,總有數目上限,也就意味著如果存入HashMap的元素太多,導致數組大小不能夠存放所有的鏈表的時候,數組大小必須要能夠調整。所以首先來考察一下數組容量的相關演算法。
第一,Entry是什麼類型?

 

 

[java] view plaincopyprint?

 
  1. static class Entry<K,V> implements Map.Entry<K,V> {  
  2.         final K key;  
  3.         V value;  
  4.         Entry<K,V> next;  
  5.         final int hash;  
  6.   
  7.         /** 
  8.          * Creates new entry. 
  9.          */  
  10.         Entry(int h, K k, V v, Entry<K,V> n) {  
  11.             value = v;  
  12.             next = n;  
  13.             key = k;  
  14.             hash = h;  
  15.         }  
  16.         ....  
  17.         public final boolean equals(Object o) {  
  18.             if (!(o instanceof Map.Entry))  
  19.                 return false;  
  20.             Map.Entry e = (Map.Entry)o;  
  21.             Object k1 = getKey();  
  22.             Object k2 = e.getKey();  
  23.             if (k1 == k2 || (k1 != null && k1.equals(k2))) {  
  24.                 Object v1 = getValue();  
  25.                 Object v2 = e.getValue();  
  26.                 if (v1 == v2 || (v1 != null && v1.equals(v2)))  
  27.                     return true;  
  28.             }  
  29.             return false;  
  30.         }  
  31.   
  32.         public final int hashCode() {  
  33.             return (key==null   ? 0 : key.hashCode()) ^  
  34.                    (value==null ? 0 : value.hashCode());  
  35.         }  
  36.         ....  


這是一個HashMap類的內部靜態類。實現了Map.Entry介面。接受兩個模板參數K和V。key和hash一旦在建構函式中被初始化,就不可改變,並且由於有next的存在,Entry可以構成一個單向鏈表。
比較重要的是equals和hashCode方法。代碼先列出來,後面再解釋。

第二,初始容量的設定
大多數都在下面的建構函式裡面.用於指定的initialCapacity不準小於0,也不能超過最大值。並且最終的capicity必須是2的n次方。還有如果使用了無參數的建構函式,預設會建立一個擁有16個元素的數組。

 

 

[java] view plaincopyprint?

 
  1. public HashMap(int initialCapacity, float loadFactor) {  
  2.         if (initialCapacity < 0)  
  3.             throw new IllegalArgumentException("Illegal initial capacity: " +  
  4.                                                initialCapacity);  
  5.         if (initialCapacity > MAXIMUM_CAPACITY)  
  6.             initialCapacity = MAXIMUM_CAPACITY;  
  7.         if (loadFactor <= 0 || Float.isNaN(loadFactor))  
  8.             throw new IllegalArgumentException("Illegal load factor: " +  
  9.                                                loadFactor);  
  10.   
  11.         // Find a power of 2 >= initialCapacity  
  12.         int capacity = 1;  
  13.         while (capacity < initialCapacity)  
  14.             capacity <<= 1;  
  15.   
  16.         this.loadFactor = loadFactor;  
  17.         threshold = (int)(capacity * loadFactor);  
  18.         table = new Entry[capacity];  
  19.         init();  
  20.     }  


第三,什麼時候應該調整數組的大小?
演算法是這樣,有一個變數size儲存了實際數組已經使用了多少個元素,並且如果size的值達到了變數threshold的值,就必須擴充數組的容量。threshold=capicity*loadFactor.capicity是數組最大的容納元素個數,loadFactor可以在建構函式中制定,否則採用預設值0.75f。capicity的最大值是1<<30(也就是2的30次方,1073741824).由此我們可以看到HashMap最多存放10億多個鏈表。
第四,如何調整數組大小?
答案是2倍,很像C++裡面的vector的分配策略。

 

 

[java] view plaincopyprint?

 
  1. void addEntry(int hash, K key, V value, int bucketIndex) {  
  2.         Entry<K,V> e = table[bucketIndex];  
  3.         table[bucketIndex] = new Entry<K,V>(hash, key, value, e);  
  4.         if (size++ >= threshold)  
  5.             resize(2 * table.length);  
  6.     }  


第五,為什麼數組大小必須是2的倍數?
在後面介紹散列值演算法的時候會回答。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.