一、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 操作(即重建內(nèi)部數(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ù)組該位置上已經(jīng)存放有其他元素了,那么在這個位置上的元素將以鏈表的形式存放,新加入的放在鏈頭,最先加入的放在鏈尾。如果數(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內(nèi)容的修改都將增加這個值,那么在迭代器初始化過程中會將這個值賦給迭代器的expectedModCount。在迭代過程中,判斷modCount跟expectedModCount是否相等,如果不相等就表示已經(jīng)有其他線程修改了Map: 注意到modCount聲明為volatile,保證線程之間修改的可見性。 |
|