1. HashMap算法
1) hashmap的數據結構 數組
Hashmap是一個數組和鏈表的結合體(在數據結構稱「鏈表散列「),以下圖示安全
當咱們往hashmap中put元素的時候,先根據key的hash值獲得這個元素在數組中的位置(即下標),而後就能夠把這個元素放到對應的位置中了。若是這個元素所在的位子上已經存放有其餘元素了,那判斷該位置上有沒有與當前key相等(equals)的元素,若是有則替換該元素的value值,若是尚未那麼在同一個位子上的元素將以鏈表的形式存放,新加入的放在鏈頭,最早加入的放在鏈尾。數據結構
key的hash值的算法:
性能
a、 當調用put(key,value)時,首先獲取key的hashcode,int hash = key.hashCode(); spa
b、 再把hash經過一下運算獲得一個int h. hash ^= (hash >>> 20) ^ (hash >>> 12); 線程
int h = hash ^ (hash >>> 7) ^ (hash >>> 4); code
爲何要通過這樣的運算呢?這就是HashMap的高明之處。先看個例子,一個十進制數32768(二進制1000 0000 0000 0000),通過上述公式運算以後的結果是35080(二進制1000 1001 0000 1000)。看出來了嗎?或許這樣還看不出什麼,再舉個數字61440(二進制1111 0000 0000 0000),運算結果是65263(二進制1111 1110 1110 1111),如今應該很明顯了,它的目的是讓「1」變的均勻一點,散列的本意就是要儘可能均勻分佈。那這樣有什麼意義呢?看第3步。 orm
c、 獲得h以後,把h與HashMap的承載量(HashMap的默認承載量【即上圖中數組的長度】length是16,能夠自動變長。在構造HashMap的時候也能夠指定一個長 度。這個承載量就是上圖所描述的數組的長度。)進行邏輯與運算,即 h & (length-1),這樣獲得的結果就是一個比length小的正數,咱們把這個值叫作index。其實這個index就是索引將要插入的值在數組中的 位置。第b步那個算法的意義就是但願可以得出均勻的index,這是HashTable的改進,HashTable中的算法只是把key的 hashcode與length相除取餘,即hash % length,這樣有可能會形成index分佈不均勻。還有一點須要說明,HashMap的鍵能夠爲null,它的值是放在數組的第一個位置。 對象
HashMap和Hashtable都實現了Map接口,但決定用哪個以前先要弄清楚它們之間的分別。主要的區別有:線程安全性,同步(synchronization),以及速度。JDK1.5之後HashTable能夠用ConcurrentHashMap來代替。
HashMap幾乎能夠等價於Hashtable,除了HashMap是非synchronized的,並能夠接受null(HashMap能夠接受爲null的鍵值(key)和值(value),而Hashtable則不行)。
HashMap是非synchronized,而Hashtable是synchronized,這意味着Hashtable是線程安全的,多個線程能夠共享一個Hashtable;而若是沒有正確的同步的話,多個線程是不能共享HashMap的。Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的擴展性更好。
另外一個區別是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。因此當有其它線程改變了HashMap的結構(增長或者移除元素),將會拋出ConcurrentModificationException,但迭代器自己的remove()方法移除元素則不會拋出ConcurrentModificationException異常。但這並非一個必定發生的行爲,要看JVM。這條一樣也是Enumeration和Iterator的區別。
因爲Hashtable是線程安全的也是synchronized,因此在單線程環境下它比HashMap要慢。若是你不須要同步,只須要單一線程,那麼使用HashMap性能要好過Hashtable。
HashMap不能保證隨着時間的推移Map中的元素次序是不變的。
1) sychronized意味着在一次僅有一個線程可以更改Hashtable。就是說任何線程要更新Hashtable時要首先得到同步鎖,其它線程要等到同步鎖被釋放以後才能再次得到同步鎖更新Hashtable。
2) Fail-safe和iterator迭代器相關。若是某個集合對象建立了Iterator或者ListIterator,而後其它的線程試圖「結構上」更改集合對象,將會拋出ConcurrentModificationException異常。但其它線程能夠經過set()方法更改集合對象是容許的,由於這並無從「結構上」更改集合。可是假如已經從結構上進行了更改,再調用set()方法,將會拋出IllegalArgumentException異常。
3) 結構上的更改指的是刪除或者插入一個元素,這樣會影響到map的結構。
HashMap能夠經過下面的語句進行同步:
Map m = Collections.synchronizeMap(hashMap);
Hashtable和HashMap有幾個主要的不一樣:線程安全以及速度。僅在你須要徹底的線程安全的時候使用Hashtable,而若是你使用Java 5或以上的話,請使用ConcurrentHashMap吧。