1. 程式人生 > >HashSet類是如何實現新增元素保證不重複的---雜湊碼的原理

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方法。