1、Set和Map關係數組
Set表明集合元素無序,集合元素不可重複的集合,Map表明一種由多個key-value組成的集合,map集合是set集合的擴展只是名稱不一樣,對應以下安全
2、HashMap的工做原理框架
public V put(K paramK, V paramV) { //若是key爲空,調用putForNullKey方法 if (paramK == null) return putForNullKey(paramV); //根據key的keyCode計算Hash值 int i = hash(paramK.hashCode()); //搜索指定hash值的對應在table中的索引 int j = indexFor(i, this.table.length); //若是j索引處的Entry不爲空,經過循環遍歷localEntry元素的下一個元素 for (Entry localEntry = this.table[j]; localEntry != null; localEntry = localEntry.next) { Object localObject1; //找到指定key與放入key相等(hash值相同,經過equals比較返回true) if ((localEntry.hash == i) && ((((localObject1 = localEntry.key) == paramK) || (paramK .equals(localObject1))))) { Object localObject2 = localEntry.value; localEntry.value = paramV; localEntry.recordAccess(this); return localObject2; } } //若是j索引Entry爲null,此處沒有Entry this.modCount += 1; //將key、value添加到i索引處 addEntry(i, paramK, paramV, j); return null; } void addEntry(int paramInt1, K paramK, V paramV, int paramInt2) { //獲取指定bucketIndex索引處Entry Entry localEntry = this.table[paramInt2]; //將新建立的Entry放入bucketIndex索引處,並讓新的Entry指向原來的Entry this.table[paramInt2] = new Entry(paramInt1, paramK, paramV, localEntry); //若是map中的key-value數量超過 if (this.size++ >= this.threshold) //table對象的長度擴充到2倍 resize(2 * this.table.length); }
put方法三種狀況,如圖:性能
get()方法:當HashMap的每一個bucket裏存儲的Entry只是單個Entry,即沒有經過指針產生Entry鏈時,此時HashMap具備最好的性能。當程序經過key取出對應value時,系統先計算出該key的hashCode()返回值,再根據該hashCode返回值找出該key在table數組中的索引,而後取出該索引處的Entry,最後返回該key對應的value值。get源碼以下:this
public V get(Object paramObject) { //若是key爲空,調用getForNullKey取出對應的value if (paramObject == null) return getForNullKey(); //根據key的hashCode值計算hash碼 int i = hash(paramObject.hashCode()); //直接取出table數組中指定索引處的值 Entry localEntry = this.table[indexFor(i, this.table.length)]; while (localEntry != null) { Object localObject; //若是該Entry的key與被搜索key相同 if ((localEntry.hash == i) && ((((localObject = localEntry.key) == paramObject) || (paramObject .equals(localObject))))) return localEntry.value; //搜索該Entry鏈的下一個 localEntry = localEntry.next; } return null; } 從代碼看出,HashMap的每一個bucket裏只有一個Entry,HashMap能夠根據索引快速取出該bucket裏的Entry。
在發生Hash衝突的狀況下,單個bucket裏存儲的不是一個Entry,而是一個Entry鏈,系統只能按順序遍歷每一個Entry,直到找到想搜索的Entry。
HashMap有兩個參數影響其性能:spa
1. 初始容量和加載因子。默認初始容量是16,加載因子是0.75。容量是哈希表中桶(Entry數組)的數量,初始容量只是哈希表在建立時的容量。加載因子是哈希表在其容量自動增長以前能夠達到多滿的一種尺度。當哈希表中的條目數超出了加載因子與當前容量的乘積時,經過調用rehash 方法將容量翻倍。線程
2. 加載因子太高雖然減小了空間開銷,但同時也增長了查詢成本(加載因子是表示Hsah表中元素的填滿的程度.若:加載因子越大,填滿的元素越多,好處是,空間利用率高了,但:衝突的機會加大了.反之,加載因子越小,填滿的元素越少,好處是:衝突的機會減少了,但:空間浪費多了)。在設置初始容量時應該考慮到映射中所需的條目數及其加載因子,以便最大限度地下降rehash 操做次數。若是初始容量大於最大條目數除以加載因子(實際上就是最大條目數小於初始容量*加載因子),則不會發生 rehash 操做。指針
3.HashMap存放的元素愈來愈多,到達臨界值(閥值)threshold時,就要對Entry數組擴容,這是Java集合類框架最大的魅力,HashMap在擴容時,新數組的容量將是原來的2倍,因爲容量發生變化,原有的每一個元素須要從新計算bucketIndex,再存放到新數組中去,也就是所謂的rehash。HashMap默認初始容量16,加載因子0.75,也就是說最多能放16*0.75=12個元素,當put第13個時,HashMap將發生rehash,rehash的一系列處理比較影響性能,因此當咱們須要向HashMap存放較多元素時,最好指定合適的初始容量和加載因子,不然HashMap默認只能存12個元素,將會發生屢次rehash操做。code
3、HashMap和Hashtable的區別對象
HashMap和Hashtable都實現了Map接口,主要的區別有:線程安全性,同步(synchronization),以及速度。HashMap幾乎能夠等價於Hashtable,除了HashMap是非synchronized的,並能夠接受null(HashMap能夠接受爲null的鍵值(key)和值(value),而Hashtable則不行)。