1. 程式人生 > >[JDK1.6] JAVA集合框架 HashSet 原始碼淺析

[JDK1.6] JAVA集合框架 HashSet 原始碼淺析

文章目錄

原始碼來自 JDK1.6

一 簡介:

此類實現 Set 介面,由雜湊表(實際上是一個 HashMap 例項)支援。它不保證 set 的迭代順序;特別是它不保證該順序恆久不變。此類允許使用 null 元素。

此類為基本操作提供了穩定效能,這些基本操作包括 addremovecontainssize,假定雜湊函式將這些元素正確地分佈在桶中。對此 set 進行迭代所需的時間與 HashSet 例項的大小(元素的數量)和底層 HashMap 例項(桶的數量)的“容量”的和成比例。因此,如果迭代效能很重要,則不要將初始容量設定得太高(或將載入因子設定得太低)。

注意,此實現不是同步的。 如果多個執行緒同時訪問一個雜湊 set,而其中至少一個執行緒修改了該 set,那麼它必須 保持外部同步。這通常是通過對自然封裝該 set 的物件執行同步操作來完成的。如果不存在這樣的物件,則應該使用 Collections.synchronizedSet 方法來“包裝” set。最好在建立時完成這一操作,以防止對該 set 進行意外的不同步訪問:

   Set s = Collections.synchronizedSet(new HashSet(...));

此類的 iterator 方法返回的迭代器是快速失敗 的:在建立迭代器之後,如果對 set 進行修改,除非通過迭代器自身的 remove 方法,否則在任何時間以任何方式對其進行修改,Iterator 都將丟擲 ConcurrentModificationException

。因此,面對併發的修改,迭代器很快就會完全失敗,而不冒將來在某個不確定時間發生任意不確定行為的風險。

注意,迭代器的快速失敗行為無法得到保證,因為一般來說,不可能對是否出現不同步併發修改做出任何硬性保證。快速失敗迭代器在盡最大努力丟擲 ConcurrentModificationException。因此,為提高這類迭代器的正確性而編寫一個依賴於此異常的程式是錯誤做法:迭代器的快速失敗行為應該僅用於檢測 bug。

此類是 Java Collections Framework 的成員。

HashSet 欄位屬性:

hashSet 裡有一個 HashMap 的屬性欄位, 和一個 Object 物件型別常量; Map的key是唯一不可重複的, set剛好也不允許元素重複, 所以HashSet 儲存元素的功能委託給了 HashMap, set的元素作為 map 的 key 儲存進去;

    private transient HashMap<E,Object> map;
    
    private static final Object PRESENT = new Object();

Set 初始化

HashSet 的構造方法, 把欄位map 例項化;
關於HashMap的實現請看這章 HashMap實現淺析

    public HashSet() {
		map = new HashMap<E,Object>();
    }
    public HashSet(int initialCapacity) {
		map = new HashMap<E,Object>(initialCapacity);
    }

HashSet 儲存元素 add(E)

儲存元素的任務直接委託給了 HashMap,

    public boolean add(E e) {
		return map.put(e, PRESENT)==null;
    }

這是一個典型的 策略模式
看下圖:
在這裡插入圖片描述

其他方法都委託給了 HashMap

注意: Set 沒有提供獲取元素的方法

獲取長度: size()

    public int size() {
		return map.size();
    }

判斷是否有元素 isEmpty()

    public boolean isEmpty() {
		return map.isEmpty();
    }

是否包含這個元素 contains

    public boolean contains(Object o) {
		return map.containsKey(o);
    }

移除元素: remove

    public boolean remove(Object o) {
		return map.remove(o)==PRESENT;
    }

清空所有元素: clear()

    public void clear() {
		map.clear();
    }

獲取迭代器 iterator()

    public Iterator<E> iterator() {
		return map.keySet().iterator();
    }