HashSet是一個依賴於HashMap的Set接口實現,容器的元素存儲和操做都是基於內部的一個HashMap實例實現,由於這個緣由,它不保證Set中元素的迭代順序特別是不保證該順序的恆久不變,容許插入null元素。該類能夠爲基本的集合操做提供穩定的性能保證,這些基本操做包括add、remove、contains和size,假定哈希函數正確地將元素分佈在底層HashMap的槽中,那麼對此HashSet進行迭代所需的時間與元素的個數和底層HashMap的槽的個數成正比的,因此迭代性能很重要的話,就不要將初始容量設置得過高(或者負載因子設置得過低)。注意HashSet不是線程安全的容器,若是有多個線程訪問該容器,且至少有一個線程對容器作告終構性修改,那麼它就必須在外部保證同步,這一般是經過對操做該容器的代碼塊加鎖實現的,若是沒有則可使用Collections.synchronizedSet在包裝它做爲一個線程安全的容器使用。HashSet的iterator返回的迭代器對象Iterator是fail-fast(快速失敗)的,如何理解,即在該迭代器建立以後任什麼時候間對該容器作告終構性修改(除了基於iterator.remve方法刪除容器元素以外)都將致使迭代器遍歷時拋出ConcurrentModificationException異常,這種快速失敗行爲沒法絕對保證,所以依賴於這個特性編寫應用程序是錯誤的。java
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable { static final long serialVersionUID = -5024744406713321676L; //底層的HashMap實例,這個對象是HashSet的核心 private transient HashMap<E,Object> map; //HashSet的元素其實就是保存在HashMap實例的KeySet集合裏,key/value鍵值對中的value就直接保存它這個固定的對象 private static final Object PRESENT = new Object(); }
HashSet繼承自AbstractSet類,該類實現了一些集合和Set基本操做方法,實現了Set接口在這裏幾乎起的相似代碼註釋的功能,由於AbstractSet自己已經實現了Set接口,經過繼承它HashSet也間接實現了Set接口,此外HashSet也實現了Clonable接口支持對象的clone()方法拷貝,實現了java.io.Serializable代表該類也支持序列化安全
/** * 構造函數,底層的HashMap實例默認的初始容量16,負載因子0.75 */ public HashSet() { map = new HashMap<>(); } /** * 構造函數,在初始化實例時將指定容器的全部元素插入容器中,底層HashMap實例默認負載因子0.75,初始化容量取基於負載 * 因子計算的容器容量和默認初始容量的較大值 */ public HashSet(Collection<? extends E> c) { map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c); } /** * 構造函數,爲底層HashMap指定初始容量和加載因子 */ public HashSet(int initialCapacity, float loadFactor) { map = new HashMap<>(initialCapacity, loadFactor); } /** * 構造函數,爲底層HashMap指定初始容量,,加載因子默認0.75 */ public HashSet(int initialCapacity) { map = new HashMap<>(initialCapacity); } /** * 構造函數,該方法屬於包私有的方法僅被LinkedHashSet使用,dummy參數僅僅只是爲了和第三個構造方法(底層是HashMap * 實例)作區分 */ HashSet(int initialCapacity, float loadFactor, boolean dummy) { map = new LinkedHashMap<>(initialCapacity, loadFactor); }
public boolean isEmpty() { return map.isEmpty(); }
很簡單容器的元素都保存在底層的HashMap實例中,因此直接判斷底層HashMap實例是否爲空。數據結構
public boolean add(E e) { return map.put(e, PRESENT)==null; }
分析方法源碼可知HashSet添加元素實際也是調用底層HashMap的put方法,將元素保存在底層HashMap實例的鍵值對key/value的key中函數
public boolean remove(Object o) { return map.remove(o)==PRESENT; }
同樣也是直接調用底層HashMap的remove方法刪除元素o源碼分析
//返回容器迭代器,無序 public Iterator<E> iterator() { return map.keySet().iterator(); } /** * 返回容器保存的元素個數 */ public int size() { return map.size(); } /** * 返回容器是否爲空 */ public boolean isEmpty() { return map.isEmpty(); } /** * 若是容器包含對象o返回true不然返回false */ public boolean contains(Object o) { return map.containsKey(o); } public Object clone() { try { HashSet<E> newSet = (HashSet<E>) super.clone(); newSet.map = (HashMap<E, Object>) map.clone(); return newSet; } catch (CloneNotSupportedException e) { throw new InternalError(e); } } /** * 序列化時調用保存對象狀態 */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { // Write out any hidden serialization magic s.defaultWriteObject(); // Write out HashMap capacity and load factor s.writeInt(map.capacity()); s.writeFloat(map.loadFactor()); // Write out size s.writeInt(map.size()); // Write out all elements in the proper order. for (E e : map.keySet()) s.writeObject(e); } /** * 反序列時調用 */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { // Read in any hidden serialization magic s.defaultReadObject(); // Read capacity and verify non-negative. int capacity = s.readInt(); if (capacity < 0) { throw new InvalidObjectException("Illegal capacity: " + capacity); } // Read load factor and verify positive and non NaN. float loadFactor = s.readFloat(); if (loadFactor <= 0 || Float.isNaN(loadFactor)) { throw new InvalidObjectException("Illegal load factor: " + loadFactor); } // Read size and verify non-negative. int size = s.readInt(); if (size < 0) { throw new InvalidObjectException("Illegal size: " + size); } capacity = (int) Math.min(size * Math.min(1 / loadFactor, 4.0f), HashMap.MAXIMUM_CAPACITY); SharedSecrets.getJavaOISAccess() .checkArray(s, Map.Entry[].class, HashMap.tableSizeFor(capacity)); // Create backing HashMap map = (((HashSet<?>)this) instanceof LinkedHashSet ? new LinkedHashMap<E,Object>(capacity, loadFactor) : new HashMap<E,Object>(capacity, loadFactor)); // Read in all elements in the proper order. for (int i=0; i<size; i++) { @SuppressWarnings("unchecked") E e = (E) s.readObject(); map.put(e, PRESENT); } } /** * 返回一個延遲綁定的迭代器 */ public Spliterator<E> spliterator() { return new HashMap.KeySpliterator<E,Object>(map, 0, -1, 0, 0); }
HashSet底層實現依賴於對象內部的一個HashMap實例,容器元素最終是以鍵值對key的形式保存在底層HashMap實例中,HashSet容器的全部操做實際操做的都是底層的HashMap實例性能