1. 程式人生 > >hashMap深入瞭解

hashMap深入瞭解

平時一直在用hashMap但是從未去了解底層原始碼。
昨天的面試恰好提到這個問題,除了能回答是通過hash表去解決hash衝突外,則一無所知。今天就對hashMap的底層原始碼一探究竟。

1.繼承和實現關係

  • Map map = new hashMap()
    一直以為是hashMap實現的map介面,現在才發現是hashMap不僅僅是實現了Map介面,還是繼承了AbstractMap,而AbstractMap也實現了Map介面。

首先來觀察頂層介面Map

  • Map 介面
public  interface Map<K,V>{
	// 內部有一個Entry介面
	// 類似於連結串列的節點,所以對map的遍歷,一般是對Entry的變數
	interface Entry<K,V>{
		//Entry 的 set/ get V 方法 
		……
	}
	// 其餘就是增刪改查方法,沒什麼可看
	……
}
  • hashMap的結構
  • 下圖是hashMap的內部類結構,一般常用的是KeySet和EntrySet
  • 驚奇的發現居然也有樹的節點TreeNode(因為認為這是hash結構,不會用樹結構)
    在這裡插入圖片描述
  • 對keySet進行觀察
    通過keySet()方法可以獲得KeySet結構
    在這裡插入圖片描述
  • 對EntrySet進行觀察
    -在這裡插入圖片描述
    方法都相同,也應該相同,因為只是map不同形式的節點表達方式。
    主要都用來遍歷Map集合。
    瞭解到HashMap的基本結構之後,那麼就要開始對構造方法進行,瞭解
  • 構造方法
    加粗樣式
    有四個構造方法。看註釋文件,神器的發現有兩個引數因子對其效能有影響(原來所不知道的)
  1. 初始容量(the initial capacity)
  2. 載入因子(loadFactory)

API文件說明:HashMap 的例項有兩個引數影響其效能:初始容量 和載入因子。容量 是雜湊表中桶的數量,初始容量只是雜湊表在建立時的容量。載入因子 是雜湊表在其容量自動增加之前可以達到多滿的一種尺度。當雜湊表中的條目數超出了載入因子與當前容量的乘積時,則要對該雜湊表進行 rehash 操作(即重建內部資料結構),從而雜湊表將具有大約兩倍的桶數。

通常,預設載入因子 (.75) 在時間和空間成本上尋求一種折衷。載入因子過高雖然減少了空間開銷,但同時也增加了查詢成本(在大多數 HashMap 類的操作中,包括 get 和 put 操作,都反映了這一點)。在設定初始容量時應該考慮到對映中所需的條目數及其載入因子,以便最大限度地減少 rehash 操作次數。如果初始容量大於最大條目數除以載入因子,則不會發生 rehash 操作。
【簡單 說,載入因子高,開闢空間小,容易rehash,載入因子小,開闢空間多,但是不容易rehash,空間換時間】(開闢空間 = 初始容量 / 載入因子)

執行緒安全問題

首先明確 hashMap是執行緒不安全的,因為沒有做任何執行緒處理(結構上的修改是指新增或刪除一個或多個對映關係的任何操作;僅改變與例項已經包含的鍵關聯的值不是結構上的修改。)這一般通過對自然封裝該對映的物件進行同步操作來完成。如果不存在這樣的物件,則應該使用 Collections.synchronizedMap方法來“包裝”該對映。最好在建立時完成這一操作,以防止對對映進行意外的非同步訪問,如下所示:

Map m = Collections.synchronizedMap(new HashMap(…));