1. 程式人生 > >HashMap、Hashtable、HashSet三種hash集合的區別

HashMap、Hashtable、HashSet三種hash集合的區別

HashMap和Hashtable的區別

  1. 兩者最主要的區別在於Hashtable是執行緒安全,而HashMap則非執行緒安全
    Hashtable的實現方法裡面都添加了synchronized關鍵字來確保執行緒同步,因此相對而言HashMap效能會高一些,我們平時使用時若無特殊需求建議使用HashMap,在多執行緒環境下若使用HashMap需要使用Collections.synchronizedMap()方法來獲取一個執行緒安全的集合(Collections.synchronizedMap()實現原理是Collections定義了一個SynchronizedMap的內部類,這個類實現了Map介面,在呼叫方法時使用synchronized來保證執行緒同步,當然了實際上操作的還是我們傳入的HashMap例項,簡單的說就是Collections.synchronizedMap()方法幫我們在操作HashMap時自動添加了synchronized來實現執行緒同步,類似的其它Collections.synchronizedXX方法也是類似原理
  2. HashMap可以使用null作為key,而Hashtable則不允許null作為key
    雖說HashMap支援null值作為key,不過建議還是儘量避免這樣使用,因為一旦不小心使用了,若因此引發一些問題,排查起來很是費事
    HashMap以null作為key時,總是儲存在table陣列的第一個節點上
  3. HashMap是對Map介面的實現,HashTable實現了Map介面和Dictionary抽象類
  4. HashMap的初始容量為16,Hashtable初始容量為11,兩者的填充因子預設都是0.75
    HashMap擴容時是當前容量翻倍即:capacity*2,Hashtable擴容時是容量翻倍+1即:capacity*2+1
  5. 兩者計算hash的方法不同
    Hashtable計算hash是直接使用key的hashcode對table陣列的長度直接進行取模
    int hash = key.hashCode();
    int index = (hash & 0x7FFFFFFF) % tab.length;

    HashMap計算hash對key的hashcode進行了二次hash,以獲得更好的雜湊值,然後對table陣列長度取摸

    複製程式碼
    static int hash(int h) {
            // This function ensures that hashCodes that differ only by
            // constant multiples at each bit position have a bounded
            
    // number of collisions (approximately 8 at default load factor). h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); } static int indexFor(int h, int length) { return h & (length-1); }
    複製程式碼
  6. HashMap和Hashtable的底層實現都是陣列+連結串列結構實現

HashSet和HashMap、Hashtable的區別

除開HashMap和Hashtable外,還有一個hash集合HashSet,有所區別的是HashSet不是key value結構,僅僅是儲存不重複的元素,相當於簡化版的HashMap,只是包含HashMap中的key而已

通過檢視原始碼也證實了這一點,HashSet內部就是使用HashMap實現,只不過HashSet裡面的HashMap所有的value都是同一個Object而已,因此HashSet也是非執行緒安全的,至於HashSet和Hashtable的區別,HashSet就是個簡化的HashMap的,所以你懂的
下面是HashSet幾個主要方法的實現

複製程式碼
  private transient HashMap<E,Object> map;
private static final Object PRESENT = new Object();
public HashSet() { map = new HashMap<E,Object>(); } public boolean contains(Object o) { return map.containsKey(o); } public boolean add(E e) { return map.put(e, PRESENT)==null; } public boolean add(E e) { return map.put(e, PRESENT)==null; } public boolean remove(Object o) { return map.remove(o)==PRESENT; } public void clear() { map.clear(); }