java集合架構-hashSet__java

來源:互聯網
上載者:User

public class HashSet<E>    extends AbstractSet<E>    implements Set<E>, Cloneable, java.io.Serializable{    static final long serialVersionUID = -5024744406713321676L;    private transient HashMap<E,Object> map;    // Dummy value to associate with an Object in the backing Map    private static final Object PRESENT = new Object();    public HashSet() {   map = new HashMap<E,Object>();    }    public HashSet(Collection<? extends E> c) {   map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));   addAll(c);    }    public HashSet(int initialCapacity, float loadFactor) {   map = new HashMap<E,Object>(initialCapacity, loadFactor);    }    public HashSet(int initialCapacity) {   map = new HashMap<E,Object>(initialCapacity);    }    HashSet(int initialCapacity, float loadFactor, boolean dummy) {   map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);    }       public Iterator<E> iterator() {   return map.keySet().iterator();    }    public int size() {   return map.size();    }       public boolean isEmpty() {   return map.isEmpty();    }      public boolean contains(Object o) {   return map.containsKey(o);    }     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();    }    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();   }    }      private void writeObject(java.io.ObjectOutputStream s)        throws java.io.IOException {   // Write out any hidden serialization magic   s.defaultWriteObject();        // Write out HashMap capacity and load factor        s.writeInt(map.capacity());        s.writeFloat(map.loadFactor());        // Write out size        s.writeInt(map.size());   // Write out all elements in the proper order.   for (Iterator i=map.keySet().iterator(); i.hasNext(); )            s.writeObject(i.next());    }    private void readObject(java.io.ObjectInputStream s)        throws java.io.IOException, ClassNotFoundException {   // Read in any hidden serialization magic   s.defaultReadObject();        // Read in HashMap capacity and load factor and create backing HashMap        int capacity = s.readInt();        float loadFactor = s.readFloat();        map = (((HashSet)this) instanceof LinkedHashSet ?               new LinkedHashMap<E,Object>(capacity, loadFactor) :               new HashMap<E,Object>(capacity, loadFactor));        // Read in size        int size = s.readInt();   // Read in all elements in the proper order.   for (int i=0; i<size; i++) {            E e = (E) s.readObject();            map.put(e, PRESENT);        }    }}

hashSet實現了Set介面,hashSet不保證迭代器的順序特別是不保證順序永久不變,hashSet中只允許存在一個null元素,對於HashSet而言,它是基於HashMap來實現的,底層採用HashMap來儲存元素。HashSet是 非同步的 。如果多個線程同時訪問一個雜湊 set,而其中至少一個線程修改了該 set,那麼它必須 保持外部同步。這通常是通過對自然封裝該 set 的對象執行同步操作來完成的。
如果不存在這樣的對象,則應該使用 Collections.synchronizedSet 方法來“封裝” set。最好在建立時完成這一操作,以防止對該 set 進行意外的不同步訪問。HashSet通過iterator()返回的 迭代器是fail-fast的。

HashSet屬性說明:

private transient HashMap<E,Object> map;


 // Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();

第一個常量:map,說明hashSet的底層是用hashMap來儲存資料的。

第二個常量:Present,由於set只用到了hashMap的key,所以,這裡定義了一個常量Object類,用來充當hashMap的value.

所以,就進一步論證了hashSet是用hashMap來實現的,只不過只用了hashMap的key,value用object對象來填充。

這裡new了一個object對象,為什麼不用null呢,new object是會在堆記憶體中開闢空間的,null是不會再堆記憶體開闢空間。如果聲明為null,可能會造成nullpointExcetion,所以為了避免這個,應該就開闢了一個8 byte的空間來存一個object對象的吧。

hashSet構造方法:

//使用HashMap的預設容量大小16和預設載入因子0.75初始化map,構造一個hashSet

  public HashSet() {
map = new HashMap<E,Object>();
    }

  /**
     * 構造一個指定Collection參數的HashSet,這裡不僅僅是Set,只要實現Collection介面的容器都可以
     */
    public HashSet(Collection<? extends E> c) {
        map = new HashMap<E,Object>(Math. max((int) (c.size()/.75f) + 1, 16));
       // 使用Collection實現的Iterator迭代器,將集合c的元素一個個加入HashSet中
       addAll(c);
    }

/**
     * 使用指定的初始容量大小和載入因子初始化map,構造一個HashSet
     */
    public HashSet( int initialCapacity, float loadFactor) {
        map = new HashMap<E,Object>(initialCapacity, loadFactor);
    }

/**
     * 不對外公開的一個構造方法(預設default修飾),底層構造的是LinkedHashMap,dummy只是一個標示參數,無具體意義
     */
    HashSet( int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);
    }

只有最後一個構造方法有寫區別,這裡構造的是LinkedHashMap,該方法不對外公開,實際上是提供給LinkedHashSet使用的,而第三個參數dummy是無意義的,只是為了區分其他構造方法。

boolean contains(Object o):其底層調用的是HashMap.containsKey(Object key)判斷是否包含指定key

HashSet add(E e):其調用的是底層HashMap中的put(K key, V value)方法,首先判斷元素(也就是key)是否存在,如果不存在則插入,如果存在則不插入,這樣HashSet中就不存在重複值

//如果此set中尚未包含指定元素,則添加指定元素
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

底層:當向HashSet集合中存入一個元素時,HashSet會調用該對象的hashCode()方法來得到該對象的hashCode值,然後根據該值確定對象在HashSet中的儲存位置。在Hash集合中,不能同時存放兩個相等的元素,而判斷兩個元素相等的標準是兩個對象通過equals方法比較相等並且兩個對象的HashCode方法傳回值也相等。

注意:對於HashSet中儲存的對象,請注意正確重寫其equals和hashCode方法,以保證放入的對象的唯一性。 HashSet remove(Object o)、clear():

//如果指定元素存在於此set中,則將其移除
    public boolean remove(Object o) {
        return map.remove(o)==PRESENT;
    }
    //從此set中移除所有元素
    public void clear() {
        map.clear();
    }

size()、isEmpty()

//返回此set中的元素的數量
    public int size() {
        return map.size();
    }
    //如果此set不包含任何元素,則返回 true
    public boolean isEmpty() {
        return map.isEmpty();
    }

HashSet迭代器:

 //返回對此 set中元素進行迭代的迭代器
    public Iterator<E> iterator() {
        return map.keySet().iterator(); //HashMap.keySet()返回<key, value>對中的key集
    }

支援序列化的寫入函數writeObject(java.io.ObjectOutputStream s)和讀取函數readObject(java.io.ObjectInputStream s):

java.io.Serializable的寫入函數,將HashSet的“總的容量,載入因子,實際容量,所有的元素”都寫入到輸出資料流中
    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException {
        // Write out any hidden serialization magic
        s.defaultWriteObject();
        // Write out HashMap capacity and load factor
        s.writeInt(map.capacity());
        s.writeFloat(map.loadFactor());
        // Write out size
        s.writeInt(map.size());
        // Write out all elements in the proper order.
        for (E e : map.keySet())
            s.writeObject(e);
    }

    // java.io.Serializable的讀取函數,將HashSet的“總的容量,載入因子,實際容量,所有的元素”依次讀出
    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        // Read in any hidden serialization magic
        s.defaultReadObject();
        // Read capacity and verify non-negative.
        int capacity = s.readInt();
        if (capacity < 0) {
            throw new InvalidObjectException("Illegal capacity: " +
                                             capacity);
        }
        // Read load factor and verify positive and non NaN.
        float loadFactor = s.readFloat();
        if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
            throw new InvalidObjectException("Illegal load factor: " +
                                             loadFactor);
        }
        // Read size and verify non-negative.
        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);
        //Create backing HashMap
        map = (((HashSet<?>)this) instanceof LinkedHashSet ?
               new LinkedHashMap<E,Object>(capacity, loadFactor) :
               new HashMap<E,Object>(capacity, loadFactor));
        // Read in all elements in the proper order.
        for (int i=0; i<size; i++) {
            @SuppressWarnings("unchecked")
                E e = (E) s.readObject();
            map.put(e, PRESENT);
        }
    }





聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.