HashMap的內部實現機制
1.HashMap的內部實現機制
HashMap是對資料結構中雜湊表(Hash Table)的實現, Hash表又叫雜湊表。Hash表是根據關鍵碼Key來訪問其對應的值Value的資料結構,它通過一個對映函式把關鍵碼對映到表中一個位置來訪問該位置的值,從而加快查詢的速度。這個對映函式叫做Hash函式,存放記錄的陣列叫做Hash表。
在Java中,HashMap的內部實現結合了連結串列和陣列的優勢,連結節點的資料結構是 Entry<k,v>,每個Entry物件的內部又含有指向下一個Entry型別物件的引用,如以下程式碼所示:
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
Entry<K,V> next; //Entry型別內部有一個自己型別的引用,指向下一個Entry
final int hash;
...
}
在HashMap的建構函式中可以看到,Entry表被申明為了陣列,如以下程式碼所示:
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR;
threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
table = new Entry[DEFAULT_INITIAL_CAPACITY];
init();
}
在以上建構函式中, 預設的 DEFAULT_INITIAL_CAPACITY值為16,DEFAULT_LOAD_FACTOR的值為0.75。
當put一個元素到HashMap中去時,其內部實現如下:
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
...
}
可以看到put函式中用一個hash函式來得到雜湊值,需要指出的是,HashTable在實現時直接用了hashCode作為雜湊值,因此採用HashMap代替HashTable有一定的優化。
put函式中用到的兩個函式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);
}
/**
* Returns index for hash code h.
*/
static int indexFor(int h, int length) {
return h & (length-1);
}
至於hash函式為什麼這樣設計,這涉及到具體雜湊函式的設計問題了,需要考慮的是雜湊演算法的時間複雜度,同時儘量使得陣列上每個位置都有值,求得時間和空間的最優。
indexFor函式則用了一個很巧妙的與運算將index值限制在了length-1之內。
當然,hash函式存在衝突的情況,同一個key對應的hash值可能相同,這時候hash值相同的元素就會用連結進行儲存,HashMap的get方法在獲取value的時候會對連結串列進行遍歷,把key值相匹配的value取出來。
2.Hash的實現
主要是雜湊演算法和衝突的解決。
3.什麼時候ReHash
在介紹HashMap的內部實現機制時提到了兩個引數,DEFAULT_INITIAL_CAPACITY和DEFAULT_LOAD_FACTOR,DEFAULT_INITIAL_CAPACITY是table陣列的容量,DEFAULT_LOAD_FACTOR則是為了最大程度避免雜湊衝突,提高HashMap效率而設定的一個影響因子,將其乘以DEFAULT_INITIAL_CAPACITY就得到了一個閾值threshold,當HashMap的容量達到threshold時就需要進行擴容,這個時候就要進行ReHash操作了,可以看到下面addEntry函式的實現,當size達到threshold時會呼叫resize函式進行擴容。
void addEntry(int hash, K key, V value, int bucketIndex) {
ntry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
if (size++ >= threshold)
resize(2 * table.length);
}
在擴容的過程中需要進行ReHash操作,而這是非常耗時的,在實際中應該儘量避免。
(原創文章,轉載請註明作者schbook:seekerxu@163.com)
相關文章
- HBase內部機制
- redis 內部機制Redis
- 模擬實現和深入理解Node Stream內部機制
- Redis處理客戶端連線的內部實現機制RXRedis客戶端
- 從原始碼的角度來談一談HashMap的內部實現原理原始碼HashMap
- WPF原始碼分析系列一:剖析WPF模板機制的內部實現(一)原始碼
- WPF原始碼分析系列一:剖析WPF模板機制的內部實現(五)原始碼
- IIS 內部執行機制
- new和instanceof的內部機制
- KVO的內部實現
- JavaScript 深入解剖bind內部機制JavaScript
- 探一探現代瀏覽器的內部機制(一)瀏覽器
- mysqldump的內部實現原理MySql
- gostring的內部實現Go
- ElasticSearch 文件(document)內部機制詳解Elasticsearch
- buffer cache 內部機制深入探索【一】
- Library cache內部機制詳解
- Oracle Library cache內部機制詳解Oracle
- HashMap的實現原理HashMap
- Angular 中攔截器的真相和 HttpClient 內部機制AngularHTTPclient
- 理解Window的新增,刪除,重新整理內部機制
- js內部事件機制–單執行緒原理JS事件執行緒
- iOS 揭露Block的內部實現原理iOSBloC
- 帶你看懂Dictionary的內部實現
- 深入 Python 字典的內部實現Python
- 深入 Python 列表的內部實現Python
- 我對備份與恢復的內部機制的理解
- MongoDB的內部架構,實現事務的原理以及資料同步和分片機制各是什麼?MongoDB架構
- SDWebImage內部實現過程Web
- Java HashMap原理及內部儲存結構JavaHashMap
- 非酋的福音?談一談遊戲內的偽隨機機制以及實現遊戲隨機
- HashMap擴容機制原始碼分析HashMap原始碼
- 簡單的 HashMap 實現HashMap
- 通過WordCount解析Spark RDD內部原始碼機制Spark原始碼
- ElasticSearch內部基於_version樂觀鎖控制機制Elasticsearch
- zt_Oracle Library cache 內部機制 說明Oracle
- 精讀《JS 陣列的內部實現》JS陣列
- kafka的內部實現、安裝和使用Kafka