HashSet怎樣保證元素不重複

都知道HashSet中不能存放重複元素,有時候能夠用來作去重操做等。可是其內部是怎麼保證元素不重複的呢?下面從源碼去看看。java

打開HashSet源碼,發現其內部維護了一個HashMap:this

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();

    /**
     * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
     * default initial capacity (16) and load factor (0.75).
     */
    public HashSet() {
        map = new HashMap<>();
    }
    ...
}

HashSet的構造方法其實就是在內部實例化了一個HashMap對象。其中還會看到一個static final的PRESENT變量,這個稍候再說,其實沒什麼實際用處。code

想知道爲何HashSet不能存放重複對象,那麼第一步固然是看它的add方法怎麼進行的判重,代碼以下:對象

public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

。。。好吧,就把元素存放在了map裏面。可是值得注意的是元素值做爲的是map的key,map的value則是前面提到的PRESENT變量,這個變量只做爲放入map時的一個佔位符而存在,因此沒什麼實際用處。ci

其實,這時候答案已經出來了:HashMap的key是不能重複的,而這裏HashSet的元素又是做爲了map的key,固然也不能重複了源碼

HashSet怎麼作到保證元素不重複的緣由找到了,文章也就結束了。。。等等,順便看一下HashMap裏面又是怎麼保證key不重複的吧,代碼以下:hash

public V put(K key, V value) {
    if (table == EMPTY_TABLE) {
        inflateTable(threshold);
    }
    if (key == null)
        return putForNullKey(value);
    int hash = hash(key);
    int i = indexFor(hash, table.length);
    for (Entry<K,V> e = table[i]; e != null; e = e.next) {
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }
    }

    modCount++;
    addEntry(hash, key, value, i);
    return null;
}

其中最關鍵的一句:it

if (e.hash == hash && ((k = e.key) == key || key.equals(k)))

調用了對象的hashCode和equals方法進行的判斷,因此又得出一個結論:若要將對象存放到HashSet中並保證對象不重複,應根據實際狀況將對象的hashCode方法和equals方法進行重寫io

相關文章
相關標籤/搜索