Java基礎之Collections框架Set實現類HashSet及其源碼分析
這個類實現了Set接口,由一個哈希表(實際上是一個HashMap實例,HashMap研究到了再說,哈哈)支持。它不能保證集合的迭代順序;特別是,它不能保證順序隨時間保持不變。這個類允許空元素。
這個類爲基本操作(添加、刪除、包含和大小)提供恆定的時間性能,假設哈希函數將元素正確地分散在bucket中。遍歷這個集合所需的時間與HashSet實例的大小(元素的數量)與支持HashMap實例的“容量”(桶的數量)的總和成正比。因此,如果迭代性能很重要,那麼不要將初始容量設置得太高(或負載係數設置得太低),這一點非常重要。
HashSet簡單使用
Set<String> example = new Hash<>();
//添加元素
example.add("tony");
example.add("project");
//移除元素
example.remove("tony");
//包含
example.contains("project");
//判斷爲空
example.isEmpty();
還有很多方法,我們來看看HastSet的源碼
HashSet源碼分析
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
{
//序列版本編號
static final long serialVersionUID = -5024744406713321676L;
//HashMap對象
private transient HashMap<E,Object> map;
// 僞值,以便與後備映射中的對象相關聯
private static final Object PRESENT = new Object();
/**
HashSet的默認構造函數,創建一個HashMap,默認大小爲16,擴容因子爲0.75
*/
public HashSet() {
map = new HashMap<>();
}
/**
* 構造一個包含指定元素的新集合,默認大小爲16,擴容因子爲0.75
* 如果集合的大小爲12的時候,初始化的大小爲17,進行了一次擴容,如果小於12的話,會返回16
*/
public HashSet(Collection<? extends E> c) {
//當c.size爲12的時候,Math.max(17,16) 返回17 max((int)(12 /0.75) + 1,16)
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
/**
創建一個hashSet,指定初始容量和擴容因子
*/
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
/**
創建一個hastSet,指定初始容量,使用默認的擴容因子 0.75
*/
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
/**
* 創建一個新的,空的 LinkedHashSet ,後臺HashMap實例是一個LinkedHashMap,具有指定的初始容量和指定的擴容因子。
*/
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
/**
返回相應當前結合的迭代器,是使用HashMap中的,可以看看hashMap的相關源碼
*/
public Iterator<E> iterator() {
return map.keySet().iterator();
}
/**
返回hashSet集合中的元素個數
*/
public int size() {
return map.size();
}
/**
返回set集合是否爲空
*/
public boolean isEmpty() {
return map.isEmpty();
}
/**
返回set集合中是否包含指定的元素
*/
public boolean contains(Object o) {
return map.containsKey(o);
}
/**
* 如果指定的元素不存在,則將其添加到此集合中
* 如果存在將返回false
*/
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();
}
/**
返回一個淺複製的HashSet
*/
@SuppressWarnings("unchecked")
public Object clone() {
try {
//這裏直接copy的是hashMap中的值
HashSet<E> newSet = (HashSet<E>) super.clone();
newSet.map = (HashMap<E, Object>) map.clone();
return newSet;
} catch (CloneNotSupportedException e) {
throw new InternalError(e);
}
}
/**
保存HashSet的狀態到相關的流中 序列化
序列化數據:HashMap實例的容量大小和擴容因子
後面是集合的大小(包含的元素數量) (int),後面是集合的所有元素(每個都是對象),沒有特定的順序。
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
// 寫出任何隱藏的序列化魔法
s.defaultWriteObject();
// 寫出HashMap 容量和擴充因子
s.writeInt(map.capacity());
s.writeFloat(map.loadFactor());
// 寫出大小
s.writeInt(map.size());
// 以適當的順序寫出所有元素
for (E e : map.keySet())
s.writeObject(e);
}
/**
* 反序列化出HashSet實例
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// 讀取任何隱藏的序列化魔法
s.defaultReadObject();
// 讀取容量並驗證非負性
int capacity = s.readInt();
if (capacity < 0) {
throw new InvalidObjectException("Illegal capacity: " +
capacity);
}
// 讀取負載因數並驗證正和非NaN
float loadFactor = s.readFloat();
if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
throw new InvalidObjectException("Illegal load factor: " +
loadFactor);
}
// 讀取集合的大小並驗證非負性
int size = s.readInt();
if (size < 0) {
throw new InvalidObjectException("Illegal size: " +
size);
}
// Set the capacity according to the size and load factor ensuring that
// the HashMap is at least 25% full but clamping to maximum capacity.
capacity = (int) Math.min(size * Math.min(1 / loadFactor, 4.0f),
HashMap.MAXIMUM_CAPACITY);
// 創建一個HashMap或者LinkedHashMap
map = (((HashSet<?>)this) instanceof LinkedHashSet ?
new LinkedHashMap<E,Object>(capacity, loadFactor) :
new HashMap<E,Object>(capacity, loadFactor));
//讀取所有的元素
for (int i=0; i<size; i++) {
@SuppressWarnings("unchecked")
E e = (E) s.readObject();
map.put(e, PRESENT);
}
}
/**
創建一個Spliterator
*/
public Spliterator<E> spliterator() {
return new HashMap.KeySpliterator<E,Object>(map, 0, -1, 0, 0);
}
}
從上面的源碼可以看出,操作HashSet就是操作HashMap中的key,key對應的都是一個空的object對象。Object PRESENT = new Object(); 因爲HashMap中的key是不能重複,是不是就可以作爲HashSet使用呢!