HashMap是基於哈希表的Map接口的非同步實現。此實現提供全部可選的映射操做,並容許使用null值和null鍵。此類不保證映射的順序,特別是不能保證該順序恆久不變。java
HashMap的數據結構:算法
在java中,最基本的結構有兩種:一是數組,而是模擬指針(引用),全部的數據結構均可以用這兩個基本結構來構造。HashMap其實是一個「鏈表散列」的數據結構,即數組和鏈表的結合體。數組
HashMap底層就是一個數組結構,數組中的每一項又是一個鏈表。當新建一個HashMap時,就會初始化一個數組。數據結構
1 transient Entry[] table; 2 static class Entry<k,V> implements Map.Entry<K,V>{ 3 final K key; 4 V value; 5 Entry<K,V> next; 6 final int hash; 7 ...... 8 }
能夠看出,Entry就是數組中的元素,每一個Map.Entry其實就是一個key-value對,它持有一個指向下一個元素的引用,這就構成了鏈表。性能
HashMap的存取實現:this
1)存儲:spa
1 public V put(K key,V value){ 2 //HashMap容許存放null值和null鍵 3 //當key爲null時,調用putForNullKey方法,將value放置在數組的一個位置。 4 if(key==null) 5 return putForNullKey(value); 6 //根據key的hashCode從新計算hash值 7 int hash=hash(key.hashCode()); 8 //搜索指定hash值在對應table中的索引 9 int i=indexFor(hash,table.length); 10 //若是i索引處的Entry不爲null,經過循環不斷遍歷e元素的下一個元素。 11 for(Entry<K,V> e=table[i];e!=null;e=e.next){ 12 Object k; 13 if(e.hash==hash&&((k=e.key)==key||key.equals(k))){ 14 V oldValue = e.value; 15 e.value = value; 16 e.recordAccess(this); 17 return oldValue; 18 } 19 } 20 // 若是i索引處的Entry爲null,代表此處尚未Entry。 21 modCount++; 22 // 將key、value添加到i索引處。 23 addEntry(hash, key, value, i); 24 return null; 25 }
從上面的源碼中能夠看出:當咱們往HashMap中put元素的時候,先根據key的hashCode從新計算hash值,根據hash值獲得這個元素在數組中的位置(即下標),若是數組該位置上已經存放了其餘元素了,那麼在這個位置上的元素將以鏈表的形式存放,新加入的放在鏈頭,最早加入的放在鏈尾。若是數組該位置上沒有元素,就直接將該元素放到此數組中的該位置上。指針
2)讀取:code
public V get(Object key) { if (key == null) return getForNullKey(); int hash = hash(key.hashCode()); for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) return e.value; } return null; }
有了上面存儲時的hash算法做爲基礎,理解起來這段代碼就很容易了。從上面的源代碼中能夠看出:從HashMap中get元素時,首先計算key的hashCode,找到數組中對應位置的某一元素,而後經過key的equals方法在對應位置的鏈表中找到須要的元素。對象
以上內容摘抄自http://beyond99.blog.51cto.com/1469451/429789
HashMap使用了特殊的值,稱做散列碼,來取代對鍵的緩慢搜索。散列碼是「相對惟一」的、用以表明對象的int值,它是經過將該對象的某些信息進行轉換而生成的。hashCode()是根類Object中的方法,所以全部的Java對象都能產生散列碼。HashMap就是使用對象的hashCode()進行快速查詢的,此方法能顯著提升性能。