Java集合框架詳解(四) HashSet
相關文章
HashSet
今天繼續對集合框架原始碼的學習 JDK1.8 今天學習HashSet
HashSet 顧名思義,就是以散列表的形式儲存資料的集合,集合中不允許相同的元素。HashSet底層是由HashMap實現的,所以在學習HashSet之前最好先學習HashMap。最後HashSet也不是執行緒安全的。下面看看類定義。
類定義
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
這個在前面幾節的分析中已經比較熟悉了,繼承了AbstractSet,實現了Set介面,Cloneable介面,以及Serializable可序列化。
成員變數
static final long serialVersionUID = -5024744406713321676L; //序列化ID
private transient HashMap<E,Object> map; //底層使用HashMap來儲存資料
private static final Object PRESENT = new Object();//新建一個object類作為底層HashMap的value
構造方法
public HashSet() {
map = new HashMap<>();//構造一個空的HashMap
}
public HashSet(Collection<? extends E> c) {
//構造一個c集合中所有元素的HashSet
//HashMap載入因子為0.75
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
public HashSet(int initialCapacity, float loadFactor) {
//建立指定初始容量以及載入因子的底層HashMap
map = new HashMap<>(initialCapacity, loadFactor);
}
public HashSet(int initialCapacity) {
//建立指定初始容量以及載入因子為0.75的HashMap
map = new HashMap<>(initialCapacity);
}
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
//以指定的initialCapacity和loadFactor構造一個新的空連結雜湊集合
//此方法不是public,只對同一個包有效果
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
HashSet常用方法
add(E e)
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
add的程式碼是將元素新增到底層的HashMap中,value和前面說的一樣使用的PRESENT,到這個地方,可以理解HashSet中元素的互異性的原因了,HashSet的元素是以Key的形式存在底層的HashMap中的,而HashMap中的Key是不允許有相同出現的,故HashSet中的元素也是不允許相同的。而return map.put(e, PRESENT)==null也很好理解,通過上一節對HashMap的put的學習,當put一個鍵值對時,如果Key存在,則替換原來的value,並且返回oldvalue,如果不存在,則建立新的entry,返回null值.
remove(Object o)
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
這裡則直接使用了HashMap的remove方法,如果刪除成功(有該元素)則返回value值(實際就是PRESENT),否則返回null。關於HashMap的方法可看上節學習。
contains(Object o)
public boolean contains(Object o) {
return map.containsKey(o);
}
public boolean containsKey(Object key) {
return getNode(hash(key), key) != null;
}
contains方法返回該元素是否在集合中,依然使用的是HashMap的containsKey方法,返回是否存在該Key的entry
isEmpty()
public boolean isEmpty() {
return map.isEmpty();
}
public boolean isEmpty() {
return size == 0;
}
這個方法非常簡單,判斷的是HashMap的size是否為0
size()
public int size() {
return map.size();
}
返回的是底層HashMap的size
Iterator()
public Iterator<E> iterator() {
return map.keySet().iterator();
}
Iterator方法返回對此set中元素進行迭代的迭代器。返回元素的順序並不是特定的。返回的是map中Key組成的集合keySet的迭代器。
clone()
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);
}
}
返回此HashSet例項的淺表副本
關於淺表副本
意思是方法中newSet只複製了當前HashSet的值,並沒有複製其引用,換言之,當克隆下來的newSet中元素髮生改變時,對原來的HashSet不會造成影響。
HashSet總結
- HashSet本身方法並不難,但是因為底層使用的是HashMap來實現,HashSet的大多數方法呼叫的都是HashMap的方法,所以,在學習HashSet方法之前,需要學習HashMap,而HashMap的方法並不簡單;
- 正是因為底層是HashMap,HashSet的元素都是存在HashMap的entry的Key中,這也實現了HashSet中元素不允許相同;
- 無序性,因為底層的HashMap是無序的,自然HashSet是無序的;
- HashSet不是執行緒安全的。