HashSet、Hashtable與HashMap的關係
一.HashSet與HashMap的關係
閱讀HashSet的源代碼,發現加上很多註釋總共就只有300多行,所以就可以猜到它的內部實現一定藉助了其他的數據結構。事實上,它就是在HashMap的基礎上實現的。在它的內部,包含了一個HashMap。
privatetransient HashMap<E,Object> map;
它的構造方法其實也是直接調用了HashMap的構造方法。
publicHashSet() {
map = new HashMap<>();
}
再來看一看它的add方法。
publicboolean add(E e) {
return map.put(e, PRESENT)==null;
}
其實就是調用了HashMap的put方法,key就是加入的e,value爲PRESENT,它是HashSet內部的一個成員變量,就是一個空的Object對象。
privatestatic final Object PRESENT = new Object();
它是一個虛值,作用就是爲了作爲value與HashMap關聯。add方法的返回值類型是boolean。通過上次分析的HashMap源碼可以知道,當放入的key值在HashMap的table數組中不存在時,即沒有hash衝突時,會把新元素加入數組中,同時返回null.所以這種情況下,add方法的返回值就是ture,表示進行了增加的操作。當放入的key,即HashSet要加入的e已經在HashMap的table數組中存在時,會用新的value覆蓋舊的value,對於HashSet來說,就是用新的PRESENT替換了舊的PRESENT。然後直接返回舊的value值,並沒有進行HashMap的插入操作。所以這個時候的add方法放入返回值就是false,表示HashSet沒有大小以及元素的改變。
相似的,HashSet的remove方法也是直接調用了HashMap的remove方法
publicboolean remove(Object o) {
return map.remove(o)==PRESENT;
}
由於HashMap的remove方法當size爲0或者要刪除的元素不存在時,會返回null,所以這時add方法的返回值就是false,表示沒有進行刪除的操作,HashSet沒有發生改變。當要刪除的元素存在時,HashMap的remove方法會返回value的值,由於在HashSet中,所有的value都是PRESENT這一個對象,所以這個時候add的返回值就是true,表示HashSet進行了刪除的操作,發生了改變。
二.Hashtable與HashMap的關係
首先發現一個比較有趣的細節問題,就是Hashtable的t沒有大寫,沒有遵循java類命名的駝峯規則。不知道什麼原因。
然後一個比較大的區別是他們的父類不同。
HashMap<K,V> extendsAbstractMap<K,V>
Hashtable<K,V> extendsDictionary<K,V>
他們的底層實現都是Entry數組,但是他們的初始默認的大小不一樣,HashMap中默認的大小是16,而Hashtable的默認大小確是11,但是他們的默認負載因子都是0.75.下面爲他的無參的構造方法:
public Hashtable() {
this(11, 0.75f);
}
然後他們的求數組下標的哈希映射的算法實現不一樣,HashMap使用的是&運算,效率相對要高一些。而Hashtable使用的是取模的餘數運算。
int index = (hash & 0x7FFFFFFF) % tab.length;
他們最大的區別就是Hashtable中所有的可能導致線程安全問題的方法都使用了synchronized修飾,加了互斥鎖。所以說Hashtable是線程安全的。但是缺點就是效率很低。他們的區別就好像Vector和ArrayList。他們還有很多的細節上的區別,大家無聊的時候可以去看看。