HashSet類是如何實現新增元素保證不重複的---雜湊碼的原理
弄清怎麼個邏輯達到元素不重複的,原始碼先上
HashSet 類中的add()方法:
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
類中map和PARENT的定義:
private transient HashMap<E,Object> map;
// Dummy value to associate with an Object in the backing Map用來匹配Map中後面的物件的一個虛擬值
private static final Object PRESENT = new Object();
put()方法:
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
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;
}
可以看到for迴圈中,遍歷table中的元素,
1,如果hash碼值不相同,說明是一個新元素,存;
如果沒有元素和傳入物件(也就是add的元素)的hash值相等,那麼就認為這個元素在table中不存在,將其新增進table;
2(1),如果hash碼值相同,且equles判斷相等,說明元素已經存在,不存;
2(2),如果hash碼值相同,且equles判斷不相等,說明元素不存在,存;
如果有元素和傳入物件的hash值相等,那麼,繼續進行equles()判斷,如果仍然相等,那麼就認為傳入元素已經存在,不再新增,結束,否則仍然新增;
可見hashcode()和equles()在此顯得很關鍵了,下面就來解讀一下hashcode和equles:
首先要明確:只通過hash碼值來判斷兩個物件時否相同合適嗎?答案是不合適的,因為有可能兩個不同的物件的hash碼值相同;
什麼是hash碼值?
在java中存在一種hash表結構,它通過一個演算法,計算出的結果就是hash碼值;這個演算法叫hash演算法;
hash演算法是怎麼計算的呢?
是通過物件中的成員來計算出來的結果;
如果成員變數是基本資料型別的值, 那麼用這個值 直接參與計算;
如果成員變數是引用資料型別的值,那麼獲取到這個成員變數的雜湊碼值後,再引數計算
如:新建一個Person物件,重寫hashCode方法
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
可以看出,Person物件內兩個引數name,age,hash碼值是這兩者計算後的記過,那麼完全有可能兩個物件name,age都不同,hash碼值相同;
下面看下equles()方法:
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
equles方法內部是分別對name,age進行判斷,是否相等。
綜合上述,在向hashSet中add()元素時,判斷元素是否存在的依據,不僅僅是hash碼值就能夠確定的,同時還要結合equles方法。