標籤:多個 操作 end 分析 不同 相等 ror 最好 否則
HashSet類,是存在於java.util包中的類 。同時也被稱為集合,該容器中只能儲存不重複的對象。底層是由HashMap來儲存的,因為HashSet不能重複,你知道HashMap的鍵不能重複就明白了這一個原理了,所以對於HashMap很熟悉的話對於HashSet就能夠很快的知道底層實現。HashMap傳送門(HashMap源碼分析)。
HashSet概述
此類實現了Set介面,由雜湊表(實際上是HashMap執行個體)支援。 對集合的迭代次序不作任何保證; 特別是不會保證這種順序會持久不變(不保證迴圈元素的順序,所以就有可能是有序的,也有可能是無序的),此類允許null元素。
這個類基本操作為add,remove,contains和size提供了穩定的時間效能,假設雜湊函數在桶中正確分散元素。 迭代該集合需要時間與HashSet執行個體的大小(元素數量)和後台HashMap執行個體的“容量”(桶數)的總和成比例。 因此,如果迭代效能很重要,不要將初始容量設定得太高(或負載因子太低)是非常重要的。
請注意,此實現不同步。如果多個線程並發訪問雜湊集,並且至少一個線程修改該集合,則必須在外部進行同步。這通常通過在自然封裝集合的某個對象上進行同步來實現。
如果沒有這樣的對象存在,則該集合應該使用Collections.synchronizedSet方法“封裝”。這最好在建立時完成,以防止意外的非同步訪問集:
Set s = Collections.synchronizedSet(new HashSet(...));
這個類的迭代器方法返回的迭代器是快速失敗的:如果在迭代器建立之後的任何時候該集合被修改,除了通過迭代器自己的remove方法之外,迭代器會以任何方式拋出ConcurrentModificationException異常。因此, 在並發修改時,迭代器會很快失效,而不是在未來不確定的時間內發生不確定性行為。
請注意,迭代器的快速失敗行為無法保證,因為一般來說,在不同步並發修改的情況下,無法做出任何硬性保證。 Fail-fast迭代器會儘力拋出ConcurrentModificationException異常。因此,編寫依賴於該異常的程式的正確性是錯誤的:迭代器的快速失敗行為只能用於檢測錯誤。(以上翻譯於JDK1.7,有錯誤請指出)
HashSet源碼分析 2.1、定義
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable
繼承AbstractSet ,該類覆蓋了 equals() 和 hashCode() 方法,以確保兩個相等的集返回相同的散列碼。若兩個集大小相等且包含相同元素,則這兩個集相等。按定義,集散列碼是集中元素散列碼的總和。因此,不論集的內部順序如何,兩個相等的集會報告相同的散列碼(百度百科)。
實現了Set介面,Set定義了集合的一些基本操作,如add、remove等等。實現了複製介面Cloneable,序列化介面Serializable。
2.2、屬性
static final long serialVersionUID = -5024744406713321676L;//序列版本號碼
private transient HashMap<E,Object> map;//私人的HashMap,E為鍵,Object為值,是不是看到底層的東西了,哈哈
private static final Object PRESENT = new Object();//與支援Map中的對象關聯的虛擬值,屬性就三個,簡單粗暴。
2.3、構造方法
public HashSet() {//構造一個新的空集合; 後台HashMap執行個體具有預設初始容量(16)和負載因子(0.75)。 map = new HashMap<>(); }
public HashSet(Collection<? extends E> c) {//構造一個包含指定集合中的元素的新集合。 HashMap使用預設負載因子(0.75)建立,初始容量足以包含指定集合中的元素。 map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));//如果c.size/0.75值大於16則大小為c.size/0.75+1,否則預設16. addAll(c); }
public HashSet(int initialCapacity, float loadFactor) {//構造一個新的空集合; 後台HashMap執行個體具有指定的初始容量和指定的負載因子。 map = new HashMap<>(initialCapacity, loadFactor);//初始容量,負載因子 }
public HashSet(int initialCapacity) {//構造一個新的空集合; 後台HashMap執行個體具有指定的初始容量和預設負載因子(0.75)。 map = new HashMap<>(initialCapacity); }
HashSet(int initialCapacity, float loadFactor, boolean dummy) {//構造一個新的,空的LinkedHashMap。 (此包私人建構函式僅由LinkedHashSet使用。)尾碼HashMap執行個體是具有指定初始容量和指定負載因子的LinkedHashMap。 map = new LinkedHashMap<>(initialCapacity, loadFactor); } 2.4、add方法
public boolean add(E e) { return map.put(e, PRESENT)==null;//map增加,終於看出來底層是map了 } 2.5、remove方法
public boolean remove(Object o) {//如果存在,則從該集合中刪除指定的元素。 return map.remove(o)==PRESENT; } 2.6、clear方法
public void clear() {//從該集合中刪除所有元素。此調用返回後,該集合將為空白。 map.clear();//使用map的clear } 2.7、clone方法
public Object clone() {//返回此<tt> HashSet </ tt>執行個體的淺層副本:元素本身不被複製。 try { HashSet<E> newSet = (HashSet<E>) super.clone();//HashSet複製 newSet.map = (HashMap<E, Object>) map.clone();//map複製 return newSet; } catch (CloneNotSupportedException e) { throw new InternalError(); } }HashSet總結
HashSet的底層採用HashMap實現,只要對HashMap熟悉,HashSet毫無壓力。要記住以下幾點:
1、HashSet可以插入Null.
2、HashSet的元素不能重複。
3、HashSet的遍曆是可能有序可能無序的。
Java集合-HashSet