HashMap源碼註釋翻譯
HashMap.java(JDK1.8)
如有錯誤翻譯的地方,歡迎評論指出。
介紹:對於HashMap及其子類而言,它們采用Hash算法來決定集合中元素的存儲位置。當系統開始初始化HashMap時,系統會創建一個長度為capacity的Entry數組,這個數組裏可以存儲元素的位置被稱為“桶(bucket)”,每個bucket都有其指定索引,系統可以根據其索引快速訪問該bucket裏存儲的元素。需要明確的是,HashMap是一個以空間換取時間的數據結構。
JDK註釋
/**
Hash table實現了Map接口。這個實現提供了對Map所有的可選擇操作,同時允許null的Key和Value(除了unsynchronized的和允許nulls,HashMap和Hashtable是大致一致的)。Hashtable這個類不保證對Map進行排序;同時不保證數據在Map裏面的順序保持不變。
假設hash方法把元素合理的散布在buckets裏面,那麽HashMap這個實現的基本操作get和put可以保持一個恒定的時間性能。collection視圖的叠代時間與HashMap實例的容量(buckets的數量)加它的大小(鍵值映射的數量)成正比。因此,如果叠代的性能比較重要,那麽設置一個不是十分高的初始容量(或很低的負載因子)是很重要的。
一個HashMap實例有兩個參數會影響其性能:初始容量和負載因子。容量是指hash table中的bucket數量,初始容量就是指hash table在被創建時的容量。負載因子是在容量自動增長之前對hash table充滿程度的一種度量。當hash table裏面的條目數超過了負載因子和當前容量的乘積時,hash table將被rehash(內部數據結構重建),這樣子hash table就會有大約兩倍於現在的bucket數量。
一般來說,默認的負載因子(0.75)在時間花費和空間占用上提供了一個比較好的權衡。更高的數值可以降低空間開銷但是增加查詢開銷(反應在HashMap類的大部分操作上,比如get和put)。Map中預期數據條目數和負載因子應該在設置初始容量時被考慮到,以便減少rehash操作次數。如果初始容量大於最大條目數除以負載因子,那麽rehash操作將不會發生。
當有許多鍵值映射要被存儲到HashMap實例中,相比於讓它按需自動rehash來增長空間,用一個足夠大的容量來創建實例存儲鍵值映射更加高效。需要註意的是,任何hash table當使用許多具有相同hashcode的key,都是一個明確會降低性能的方式。為了改善影響,當keys是可比較的,這個類可以在keys之間使用比較來排序幫助斷開關聯。
需要註意的是,這個實現不是同步的。如果有多個線程同時訪問hash map,並且至少有一個線程對map進行了結構性修改,這在外部必須用synchronized進行修飾(結構性修改指的是對一個或多個鍵值映射進行增刪的操作;僅僅只是修改實例現有key的value並不屬於結構新修改)。這通常是通過對自然封裝map的那個對象進行同步來實現的。
如果沒有這樣的對象存在,那麽map應該用Collections.synchronizedMap()方法來包裹。這最好在創建的時候,已避免意外的對map的非同步訪問。
Map m = Collections.synchronizedMap(new HashMap(…));
這個類由“集合視圖方法”返回的叠代器都是“fail-fast”的:如果map在叠代器被創建後的任何時間點裏被結構性修改了,除了叠代器自己的remove方法,其它任何方法都會引起叠代器拋出ConcurrentModificationException的異常。因此,當面臨同時的修改時,叠代器將幹凈的迅速的fails,而不是冒著在將來的不確定時間點出現的任意的不確定的形式的風險。
需要註意的是,叠代器的fail-fast表現不能保證和其定義的一樣,一般來說,在存在不同步的同時修改情況下是不可能做出明確的保證的。Fail-fast叠代器在盡最大努力的基礎上拋出ConcurrentModificationException異常。因為,編程時依賴捕獲這個異常來確保正確性是錯誤的做法:叠代器的fail-fast特性只應該被用於檢測bugs。
**/
JDK參數
/**
默認初始容量 – 必須是2的次方
**/
DEFAULT_INITIAL_CAPACITY = 1 << 4 (16)
/**
最大容量,如果一個更高的值被構造函數用參數隱式指定,那麽依舊使用和這個容量
必須是2的次方
**/
MAXIMUM_CAPACITY = 1 << 30 (2的30次方)
/**
當沒有在構造函數裏面指定,將使用這個默認負載因子
**/
DEFAULT_LOAD_FACTOR = 0.75
/**
一個bucket的樹化閾值(紅黑樹)
為bin使用tree還是list一個bin數目閾值。在至少達到這個數目節點的情況下增加元素,bins將會轉化成tree。該值必須大於2,至少應該是8,與移除樹的假設相適應。
**/
TREEIFY_THERSHOLD = 8
/**
一個樹的鏈表還原閾值
在調整大小操作時反樹化(切分)一個bin的bin數目閾值,在移除時檢測最大是6。
**/
UNTREEIFY_THRESHOLD = 6
/**
樹形化時bins的最小哈希表容量(否則如果bin中有太多的節點就對哈希表調整大小)。為避免在調整大小和樹形化閾值之間產生矛盾,這個值至少是4 * TREEIFY_THERSHOLD。
**/
MIN_TREEIFY_CAPACITY = 64
/**
table,在第一次使用時被初始化,必要時會調整大小。被分配後,其長度一直是2的次方(在當前不需要的引導機制下,我們也容許在一些操作中其長度為0)。
**/
Node<K,V>[] table
/**
擁有緩存的entrySet()。需要註意的是,AbstractMap域裏面使用的是keySet()和values()。
**/
Set<Map.Entry<K,V>> entrySet
/**
這個map裏面包含的鍵值對的個數
**/
int size
/**
這個HashMap被結構性修改的次數。結構性修改是那些改變了HashMap裏面鍵值對個數或其它它的內部結構修改(例如rehash)。這個域是用於叠代器在集合視圖中的fail-fast。
**/
int modCount
/**
需要進行調整大小時的閾值(capacity*load factor)
**/
int threshold
/**
Hash table的負載因子
**/
float loadFactor
HashMap源碼註釋翻譯