關於hashcode 和 equals 的內容總結


第一:equals() 的作用是 表示其他對象是否“等於”這個對象。

在Object源碼里面    equals的作用等價於 ==   即 用來比較倆個對象的內存地址是否相同

 

public boolean equals(Object obj) { return (this == obj); }

 

但是一般我們是想用equals來表示   倆個對象的內容是否相同的   所以需要我們去覆蓋 equals的方法 

以String類 的 equals方法為例   用來比較兩個對象的內容是否相同

 

   public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

 

如果自定義的對象在沒有重寫equals方法的前提下   使用   equals 的話  那么執行的是 ==     即比較倆個對象的內存地址是否相同

在重寫equals方法的原則    (現在的IDE  基本都可以自動重寫 equals方法了   要是沒有特殊的需求  可以直接調用  就能使用了  熊重寫equals方法的時候  還需要重寫 hashcode )

1. 對稱性:如果x.equals(y)返回是"true",那么y.equals(x)也應該返回是"true"。
2. 反射性:x.equals(x)必須返回是"true"。
3. 類推性:如果x.equals(y)返回是"true",而且y.equals(z)返回是"true",那么z.equals(x)也應該返回是"true"。
4. 一致性:如果x.equals(y)返回是"true",只要x和y內容一直不變,不管你重復x.equals(y)多少次,返回都是"true"。
5. 非空性,x.equals(null),永遠返回是"false";x.equals(和x不同類型的對象)永遠返回是"false"。

第二:hashCode() 的作用是獲取哈希碼,也稱為散列碼;它實際上是返回一個int整數。這個哈希碼的作用是確定該對象在哈希表中的索引位置。

   關於hashcode 在數據結構的 查找中 有介紹    它的作用是為了 方便查找      查找的時間理論上是0(1)  在一個對象集合中(hashmap  hashset  ..)  你可以根據一個對象的哈希碼  在哈希表上 迅速的找到它所對應的值   

哈希表的介紹

 

那么hashcode  和 equals 有什么聯系呢?

為什么在重寫equals的時候  一般都是要重寫hashcode呢?

其實吧  說有關系也有關系  說沒有關系也沒有關系 

第一:   如果你的這個類是  單單的用來做比較倆者的內容    並不把它們存放到   集合當中(hashmap, hashset。。。。)當中的話 他們是沒有任何關系的 

 

第二:  如果你要是把他們存放到 集合當中hashmap, hashset。。。。)  那他們就很有關系了   

 為什么 ?  這是因為hashcode的設計的目的 決定的    hashcode的 目的 就是為了   在集合中對對象進行查找 

hashCode是jdk根據對象的地址或者字符串或者數字算出來的int類型的數值 詳細了解請 參考 public int hashCode()返回該對象的哈希碼值。支持此方法是為了提高哈希表(例如 java.util.Hashtable 提供的哈希表)的性能。

如何要是不理解的話  可以去  看一下  哈希表的作用    哈希表你可以想象為一個數組    那么哈希碼就是  數組的坐標    坐標里面的值就時  對象       然后通過哈希嗎來訪問響應的對象   這樣的方式大大的加快了訪問速率

由於哈希碼生成算法的不同  難免會發生沖突      即內容不同的對象  生成的哈希嗎卻相同     關於處理沖突的方式 有很多種 這里   這說一種   鏈地址法 

 

 

 java的 集合(hashmap   hashset 采用的就是類似於這樣的方法 )

說到這里應該差不多知道 hashcode和 equals的關系了吧   即通過hashcode 定位到  具體的位置 然后通過 equals比較 這個位置的對象的內容是否和原來的相同   

從而生成 各種集合操作  如

hashmap中的 get 操作 看源碼

public V get(Object key) {
    if (key == null)
        return getForNullKey();
    // 獲取key的hash值
    int hash = hash(key.hashCode());
    // 在“該hash值對應的鏈表”上查找“鍵值等於key”的元素
    for (Entry<K,V> e = table[indexFor(hash, table.length)];
         e != null;
         e = e.next) {
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
            return e.value;
    }
    return null;
}

put操作   put() 的作用是對外提供接口,讓HashMap對象可以通過put()將“key-value”添加到HashMap中

public V put(K key, V value) {
    // 若“key為null”,則將該鍵值對添加到table[0]中。
    if (key == null)
        return putForNullKey(value);
    // 若“key不為null”,則計算該key的哈希值,然后將其添加到該哈希值對應的鏈表中。
    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;
        // 若“該key”對應的鍵值對已經存在,則用新的value取代舊的value。然后退出!
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }
    }

    // 若“該key”對應的鍵值對不存在,則將“key-value”添加到table中
    modCount++;
    addEntry(hash, key, value, i);
    return null;
}

都是 hashcode和equals 的 合並操作 

 

注意  : hashcode的 重寫   要使得對象生成的hashcode盡量避免沖突(即重復)

另外      一般 

        1)、如果兩個對象相等,那么它們的hashCode()值一定相同。
              這里的相等是指,通過equals()比較兩個對象時返回true。
        2)、如果兩個對象hashCode()相等,它們並不一定相等。
               因為在散列表中,hashCode()相等,即兩個鍵值對的哈希值相等。然而哈希值相等,並不一定能得出鍵值對相等。

==================================================================================

補充學習    string 的hashcode

 

     */
    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

最有意思的是 Integer類型的    hashcode的值  就是  內容的值  

        /**
     * Compares this object to the specified object.  The result is
     * {@code true} if and only if the argument is not
     * {@code null} and is an {@code Integer} object that
     * contains the same {@code int} value as this object.
     *
     * @param   obj   the object to compare with.
     * @return  {@code true} if the objects are the same;
     *          {@code false} otherwise.
     */
    public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

    
        /**
     * Returns a hash code for a {@code int} value; compatible with
     * {@code Integer.hashCode()}.
     *
     * @param value the value to hash
     * @since 1.8
     *
     * @return a hash code value for a {@code int} value.
     */
    public static int hashCode(int value) {
        return value;
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM