生活随笔
收集整理的這篇文章主要介紹了
HashMap HashTable HashSet区别剖析
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
HashMap、HashSet、HashTable之間的區別是Java程序員的一個常見面試題目,在此僅以此博客記錄,并深入源代碼進行分析:
在分析之前,先將其區別列于下面
1:HashSet底層采用的是HashMap進行實現的,但是沒有key-value,只有HashMap的key set的視圖,HashSet不容許重復的對象
2:Hashtable是基于Dictionary類的,而HashMap是基于Map接口的一個實現
3:Hashtable里默認的方法是同步的,而HashMap則是非同步的,因此Hashtable是多線程安全的
4:HashMap可以將空值作為一個表的條目的key或者value,HashMap中由于鍵不能重復,因此只有一條記錄的Key可以是空值,而value可以有多個為空,但HashTable不允許null值(鍵與值均不行)
5:內存初始大小不同,HashTable初始大小是11,而HashMap初始大小是16
6:內存擴容時采取的方式也不同,Hashtable采用的是2*old+1,而HashMap是2*old。
7:哈希值的計算方法不同,Hashtable直接使用的是對象的hashCode,而HashMap則是在對象的hashCode的基礎上還進行了一些變化
源代碼分析:
對于區別1,看下面的源碼
?
[java]?view plaincopy
public?class?HashSet<E>??????extends?AbstractSet<E>??????implements?Set<E>,?Cloneable,?java.io.Serializable??{???????static?final?long?serialVersionUID?=?-5024744406713321676L;??????????private?transient?HashMap<E,Object>?map;????????????????private?static?final?Object?PRESENT?=?new?Object();????????????????public?HashSet()?{??????map?=?new?HashMap<E,Object>();??????}?? 從上面的代碼中得出的結論是HashSet的確是采用HashMap來實現的,而且每一個鍵都關鍵同一個Object類的對象,因此鍵所關聯的值沒有意義,真正有意義的是鍵。而HashMap里的鍵是不允許重復的,因此1也就很容易明白了。
?
對于區別2,繼續看源代碼如下
?
[java]?view plaincopy
public?class?Hashtable<K,V>??????extends?Dictionary<K,V>??????implements?Map<K,V>,?Cloneable,?java.io.Serializable?{?? [java]?view plaincopy
public?class?HashMap<K,V>??????extends?AbstractMap<K,V>??????implements?Map<K,V>,?Cloneable,?Serializable?? 區別3,找一個具有針對性的方法看看,這個方法就是put
?
?
[java]?view plaincopy
public?synchronized?V?put(K?key,?V?value)?{??????????????if?(value?==?null)?{??????????throw?new?NullPointerException();??????}????????????Entry?tab[]?=?table;??????????int?hash?=?key.hashCode();??????????int?index?=?(hash?&?0x7FFFFFFF)?%?tab.length;??????????for?(Entry<K,V>?e?=?tab[index]?;?e?!=?null?;?e?=?e.next)?{??????????????????if?((e.hash?==?hash)?&&?e.key.equals(key))?{??????????????????V?old?=?e.value;??????????????????e.value?=?value;??????????????????return?old;??????????}??????}??????????modCount++;??????if?(count?>=?threshold)?{??????????????????rehash();????????????????tab?=?table;??????????????index?=?(hash?&?0x7FFFFFFF)?%?tab.length;??????}?? [java]?view plaincopy
????public?V?put(K?key,?V?value)?{??????????????????if?(key?==?null)??????????????return?putForNullKey(value);??????????????int?hash?=?hash(key.hashCode());??????????int?i?=?indexFor(hash,?table.length);??????????????for?(Entry<K,V>?e?=?table[i];?e?!=?null;?e?=?e.next)?{??????????????Object?k;??????????????????????????if?(e.hash?==?hash?&&?((k?=?e.key)?==?key?||?key.equals(k)))?{??????????????????V?oldValue?=?e.value;??????????????????e.value?=?value;??????????????????e.recordAccess(this);??????????????????return?oldValue;??????????????}??????????}??????????????????modCount++;??????????addEntry(hash,?key,?value,?i);??????????return?null;??????}?? 區別4在上面的代碼中,已經分析了,可以再細看一下
?
區別5內存初化大小不同,看看兩者的源代碼:
?
[java]?view plaincopy
?public?Hashtable()?{???????????this(11,?0.75f);???}?? [java]?view plaincopy
?public?HashMap()?{????????this.loadFactor?=?DEFAULT_LOAD_FACTOR;????????threshold?=?(int)(DEFAULT_INITIAL_CAPACITY?*?DEFAULT_LOAD_FACTOR);????????table?=?new?Entry[DEFAULT_INITIAL_CAPACITY];???????init();???}?? 從上面的代碼中,可以看出的是兩者的默認大小是不同的,一個是11,一個是16
?
區別6內存的擴容方式,看一看源代碼也是很清楚的,其實區別是不大的,看到網上一哥們寫的,說兩者有區別,其實真正深入源碼,區別真不大,一個是2*oldCapacity+1, 一個是2*oldCapacity,你說大嗎:)
?
[java]?view plaincopy
protected?void?rehash()?{??????????int?oldCapacity?=?table.length;??????Entry[]?oldMap?=?table;????????int?newCapacity?=?oldCapacity?*?2?+?1;??????????Entry[]?newMap?=?new?Entry[newCapacity];????????modCount++;??????threshold?=?(int)(newCapacity?*?loadFactor);??????table?=?newMap;????????for?(int?i?=?oldCapacity?;?i--?>?0?;)?{??????????for?(Entry<K,V>?old?=?oldMap[i]?;?old?!=?null?;?)?{??????????Entry<K,V>?e?=?old;??????????old?=?old.next;????????????int?index?=?(e.hash?&?0x7FFFFFFF)?%?newCapacity;??????????e.next?=?newMap[index];??????????newMap[index]?=?e;??????????}??????}??????}?? [java]?view plaincopy
void?addEntry(int?hash,?K?key,?V?value,?int?bucketIndex)?{??Entry<K,V>?e?=?table[bucketIndex];?????????table[bucketIndex]?=?new?Entry<K,V>(hash,?key,?value,?e);????????????????if?(size++?>=?threshold)????????????????????resize(2?*?table.length);?????}?? 是吧,沒什么區別吧
?
對于區別7的哈希值計算方法的不同,源碼面前,同樣是了無秘密
?
[java]?view plaincopy
int?hash?=?key.hashCode();??int?index?=?(hash?&?0x7FFFFFFF)?%?tab.length;?? [java]?view plaincopy
int?hash?=?hash(key.hashCode());??int?i?=?indexFor(hash,?table.length);?? 上面的HashMap中可以看出關鍵在兩個函數hash與indexFor
?
源碼如下:
?
[java]?view plaincopy
static?int?hash(int?h)?{??????????????????????h?^=?(h?>>>?20)?^?(h?>>>?12);??????return?h?^?(h?>>>?7)?^?(h?>>>?4);??}?? [java]?view plaincopy
?static?int?indexFor(int?h,?int?length)?{???????return?h?&?(length-1);???}?
轉載于:https://www.cnblogs.com/dangzhenjiuhao/p/5416470.html
總結
以上是生活随笔為你收集整理的HashMap HashTable HashSet区别剖析的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。