Java集合類之HashMap源碼分析
hash表是一種常見的數據結構,主要是通過hash算法將數據盡可能的散列開來存放,當要查找某一數據時,可以通過hash算法直接定位,節省了對比查找的時間。map是一種key、value形式的鍵值對,將hash表和map結合即形成了HashMap。
在Java中HashMap的數據是以Entry
HashMap的存儲數據的示例圖如下:
HashMap 的put方法的源碼解析
public V put(K key, V value) { if (key == null) return putForNullKey(value); // HashMap接收key為null的數據 int hash = hash(key.hashCode()); //對key的hashCode再進行hash運算 int i = indexFor(hash, table.length);//根據hash值和entry數組的大小計算出新增數據應該存放的數組位置 for (Entry<K,V> e = table[i]; e != null; e = e.next) { // for循環遍歷找到的數組下標的entry,如果hash值和key都相等,則覆蓋原來的value值
Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } }modCount++; //如果上面for循環沒有找到相同的hash和key,則增加一個entry addEntry(hash, key, value, i); return null; }</K,V></pre> <p></p>
void addEntry(int hash, K key, V value, int bucketIndex) { Entrye = table[bucketIndex]; //找到下標的entry //new 一個新的entry,賦值給當前下標數組 table[bucketIndex] = new Entry (hash, key, value, e); if (size++ >= threshold) resize(2 * table.length); } Entry(int h, K k, V v, Entryn) { value = v; next = n; //即將原來數組下標對應的entry賦值給新的entry的next key = k; hash = h; } (1)hash值相同且key相等數據將被覆蓋。
(2)添加新的entry時,將已存在的數據下標的entry(可能是null)賦值給新entry的next,新entry將替換原數組下標的值。
HashMap的get方法源碼解析
public V get(Object key) { //key為null時特別處理 if (key == null) return getForNullKey(); int hash = hash(key.hashCode()); //indexFor(hash, table.length) 根據hash值和數組長度計算出下標,然后遍歷Entry鏈表 for (Entrye = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) return e.value; } return null; } 總結
- 一個對象當HashMap的key時,必須覆蓋hashCode()和equals()方法,hashCode()的返回值盡可能的分散。
- 當HashMap的entry的數組足夠大,key的hash值足夠分散時,即是可以實現一個entry數組下標最多只對應了一個entry,此時get方法的時間復雜度可以達到O(1)。
- 在數組長度和get方法的速度上要達到一個平衡。數組比較長碰撞出現的概率就比較小,所以get方法獲取值時就比較快,但浪費了比較多的空間;當數組長度沒有冗余時,碰撞出現的概率比較大,雖然節省了空間,但會犧牲get方法的時間。
- HashMap有默認的裝載因子loadFactor=0.75,默認的entry數組的長度為16。裝載因子的意義在于使得entry數組有冗余,默認即允許25%的冗余,當HashMap的數據的個數超過12(16*0.75)時即會對entry數組進行第一次擴容,后面的再次擴容依次類推。
- HashMap每次擴容一倍,resize時會將已存在的值從新進行數組下標的計算,這個是比較浪費時間的。在平時使用中,如果能估計出大概的HashMap的容量,可以合理的設置裝載因子loadFactor和entry數組初始長度即可以避免resize操作,提高put的效率。
- HashMap不是線程安全的,多線程環境下可以使用Hashtable或ConcurrentHashMap。
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!