一,、HashMap和HashTable 區(qū)別: 2.HashTable中的方法是同步的,而HashMap中方法是非同步的.也就是說,在多線程的情況下用HashMap需要額外的同步機制. Map Collections.synchronziedMap(Map m)這個方法返回一個同步的Map,封裝了底層的HashMap方法,使得多線程安全. 或者采用ConcurrentMap接口; 3.HashMap中,鍵和值都可以為null(null鍵只能有一個),,HashTable不允許為null。當get()方法時返回null,,即表示沒有該鍵,,也可以表示該鍵對應的值為null。因此判斷HashMap里是否存在某個鍵時,,不能用get()方法,,應該用containsKey()方法 相同: 1.有兩個參數(shù)影響性能:初始容量和加載因子。 初始容量:哈希表創(chuàng)建時的容量,,初始容量設置太高可能會浪費空間,; 加載因子:對哈希表在其容量自動增加之前可以達到多滿的一個尺度(默認為.75),加載因子過高雖然減少了空間開銷,,但同時也增加了查詢成本,。 當哈希表中的條目數(shù)超出了加載因子與當前容量的乘積時,則要對該哈希表進行 rehash 操作(即重建內部數(shù)據(jù)結構),。 2.所有類的“Collection視圖方法”返回的Collection的iterator方法返回的迭代器是快速失敗的,。 二、HashMap中key和value的原理 HashMap是基于哈希表的Map接口的非同步實現(xiàn),。此實現(xiàn)提供所有可選的映射操作,,并允許使用null值和null鍵。HashMap實際上是一個“鏈表散列”的數(shù)據(jù)結構,,即數(shù)組和鏈表的結合體,。HashMap底層就是一個數(shù)組結構,數(shù)組中的每一項又是一個鏈表,。當新建一個HashMap的時候,,就會初始化一個數(shù)組。每個Map.Entry是一個Key-Value對,,也是數(shù)組中的元素,,它持有指向下一個元素的引用,,這就構成了鏈表。 HashMap的存取實現(xiàn):1) 存儲: 當我們往HashMap中put元素的時候,,先根據(jù)key的hashCode重新計算hash值,,根據(jù)hash值得到這個元素在數(shù)組中的位置(即下標),如果數(shù)組該位置上已經存放有其他元素了,,那么在這個位置上的元素將以鏈表的形式存放,新加入的放在鏈頭,,最先加入的放在鏈尾,。如果數(shù)組該位置上沒有元素,就直接將該元素放到此數(shù)組中的該位置上,。 當系統(tǒng)決定存儲HashMap中的key-value對時,,完全沒有考慮Entry中的value,僅僅只是根據(jù)key來計算并決定每個Entry的存儲位置,。我們完全可以把 Map 集合中的 value 當成 key 的附屬,,當系統(tǒng)決定了 key 的存儲位置之后,value 隨之保存在那里即可,。hash(int h)--計算hash值的方法根據(jù)key的hashCode重新計算一次散列,。此算法加入了高位計算,防止低位不變,,高位變化時,,造成的hash沖突。 2) 讀?。?/p> 從HashMap中get元素時,,首先計算key的hashCode,找到數(shù)組中對應位置的某一元素,,然后通過key的equals方法在對應位置的鏈表中找到需要的元素,。 3)Fail-Fast機制:我們知道java.util.HashMap不是線程安全的,因此如果在使用迭代器的過程中有其他線程修改了map,,那么將拋出ConcurrentModificationException,,這就是所謂fail-fast策略。 這一策略在源碼中的實現(xiàn)是通過modCount域,,modCount顧名思義就是修改次數(shù),,對HashMap內容的修改都將增加這個值,那么在迭代器初始化過程中會將這個值賦給迭代器的expectedModCount,。在迭代過程中,,判斷modCount跟expectedModCount是否相等,如果不相等就表示已經有其他線程修改了Map: 注意到modCount聲明為volatile,,保證線程之間修改的可見性,。 |
|