Java集合-HashSet
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
繼承AbstractSet ,該類覆蓋了 equals 和 hashCode 方法,以確保兩個相等的集返回相同的散列碼。若兩個集大小相等且包含相同元素,則這兩個集相等。按定義,集散列碼是集中元素散列碼的總和。因此,不論集的內部順序如何,兩個相等的集會報告相同的散列碼(百度百科)。
實現了Set介面,Set定義了集合的一些基本操作,如add、remove等等。實現了克隆介面Cloneable,序列化介面Serializable。
2.2、屬性static final long serialVersionUID = -5024744406713321676L;//序列版本號
private transient HashMap
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 {//返回此 HashSet tt>實例的淺層副本:元素本身不被克隆。 HashSet總結 HashSet的底層採用HashMap實現,只要對HashMap熟悉,HashSet毫無壓力。要記住以下幾點: 1、HashSet可以插入Null. 2、HashSet的元素不能重複。
try {
HashSet
newSet.map = (HashMap
return newSet;
} catch (CloneNotSupportedException e) {
throw new InternalError;
}
}
3、HashSet的遍歷是可能有序可能無序的。
※為什麼多線程、junit 中無法使用spring 依賴注入?
※OS X 和iOS 中的多線程技術(上)
※View Components as Tag Helpers,離在線模板編輯又進一步
※淺談MVC Form認證
※asp.net core中負載均衡場景下http重定向https的問題
TAG:科技優家 |