1. 程式人生 > >Java集合框架詳解(四) HashSet

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不是執行緒安全的。