Java編程思想之 ------ 再談重寫equals需要重寫hashcode?

這其實是個老生常談的問題了,不過還是有人不理解,所以這裏就總結一下

一、介紹

我們知道任何對象都直接或者間接繼承Object類,而我們今天要探討的問題就定義在Object中,瞅一瞅

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

public native int hashCode();

可以看出來,equals方法在Object類中默認實現,其含義是比較兩個引用所指向的對象是否一樣(仔細理解一下)

而hashcode方法是native關鍵字修飾的,那麼它其實調用的是 定義在DLL庫(動態鏈接庫)中的實現。
google一下就知道hashcode在Object中的實現是利用內存地址獲得hashcode值
根據hashcode的註釋可以看到(看不到的自己看看源碼,太長這裏就不粘了)。
總的理念就兩條,

  • equals方法相等,hashcode一定相等
  • equals方法不等,hashcode不一定相等

二、品一品

從上面總結的定義可以看到,重寫equals方法必須要重寫hashcode方法其實是官方定義的,因爲當你重寫equals方法判斷兩個對象相等之後,不重寫hashcode的話hashcode就不一定相等了,這就違反了第一條規則。

但是經過試驗,其實重寫hashcode影響並不大,因爲當你顯示調用equals方法判斷兩個對象的時候就只涉及到equals方法的內容!和hashcode沒半毛錢關係(除非你在equals調用了hashcode )

所以重寫equals方法不一定要重寫hashcode方法?
但是你要明白,hashcode出現得有意義呀,不然爲什麼要有這個方法呢。
所以從設計的角度來看,重寫equals方法是必須要重寫hashcode方法,從而使它滿足上面兩條規則。(官方定義的,咱也沒辦法)

三、意義

那麼hashcode真正的意義在哪呢?
爲什麼一定要抱着equals方法一定要抱着hashcode一塊死?

emmmmmmm…
前面您也看到了,我說的是顯示調用equals方法!!!,當你調用別人的equals方法時,你保證別人不用hashcode方法???
看看最常用HashMap,瞭解一哈它的put方法流程

  1. 向HashMap添加元素的時候,需要先定位到在數組的位置(採用hashCode方法)。
  2. 如果只重寫了 equals 方法,兩個鍵的 equals 返回了true,集合是不允許出現重複鍵的,只能插入一個。
  3. 此時如果沒有重寫 hashCode 方法,那麼就無法定位到同一個位置,集合還是會插入鍵。這樣集合中就出現了重複鍵了。那麼重寫的equals方法就沒有意義了。所以一定要重寫!

貼個例子

import java.util.HashMap;
import java.util.Map;

public class HashTest {
    private String name;
    private String age;

    public HashTest(String name, String age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }


    @Override
    public boolean equals(Object obj) {
        if(this.name==((HashTest)obj).name){
            return true;
        }
        return false;
    }

    public static void main(String []args){
        HashTest hashTest1=new HashTest("ming","12");
        HashTest hashTest2=new HashTest("ming","12");
        Map<HashTest,String> map=new HashMap<>();
        map.put(hashTest1,"ming1");
        map.put(hashTest2,"ming2");
        //map長度爲2
    }

}

可能有些小夥伴還反應不過來。解釋以下八…
這段邏輯代碼我們想實現的是map中以HashTest對象爲key,從代碼可以看出來,hashTest1和hashTest2應該是同一個對象,但是實際map中存儲時卻當作兩個不同的key來處理,想一想這段代碼是不是就與預期的實現不符!!!就是出現問題嘍!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章