都知道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