為什么覆蓋了equals就必須覆蓋hashCode?


two.jpg

很多人可能都知道,在每個覆蓋了equals方法的類中,也必須覆蓋hashCode方法;但是這里面的原因是什么呢?

我想應(yīng)該從兩個方面闡述這個問題:

  • 什么情況下需要覆蓋equals
  • 在覆蓋了equals的同時未覆蓋hashCode會導(dǎo)致什么問題?

第一個問題,什么情況下需要覆蓋equals呢?首先我們需要知道,如果不覆蓋equals,由于每個類的實(shí)例在內(nèi)存中都是唯一的,那么就無法做到兩個業(yè)務(wù)上等同的實(shí)例equals也返回true,所以說覆蓋equals一般都是業(yè)務(wù)需要,即有些場景下只需要對象的關(guān)鍵屬性相等,就認(rèn)為他們相等

其次,如果在覆蓋了equals的同時未覆蓋hashCode會導(dǎo)致什么問題呢?這個問題的答案在于:如果沒有遵守覆蓋equals時同時覆蓋hashCode,就會違反Object.hashCode的通用約定(具體的約定大家可以至ObejcthashCode方法注釋處查看),從而導(dǎo)致該類無法結(jié)合所有基于散列的集合一起正常工作,這樣的集合包括HashMap,HashSetHashTable,有點(diǎn)難理解是嗎?沒關(guān)系,舉例說明就清楚了,假設(shè)有一個PhoneNumber類,只需兩個實(shí)例的prefixlineNumber屬性相等,即可認(rèn)為兩個PhoneNumber相等:

public class PhoneNumber {
    private short areaCode;
    private short prefix;//關(guān)鍵屬性
    private short lineNumber;//關(guān)鍵屬性

    public PhoneNumber(short areaCode, short prefix, short lineNumber) {
        this.areaCode = areaCode;
        this.prefix = prefix;
        this.lineNumber = lineNumber;
    }

    public boolean equals(Object o) {
        if(o == this) {
            return true;
        }

        if(!(o instanceof PhoneNumber)) {
            return false;
        }

        PhoneNumber compareO = (PhoneNumber)o;

        return compareO.prefix == this.prefix
                && compareO.lineNumber == this.lineNumber;
    }
}

然后將PhoneNumberHashMap一起使用:

Map<PhoneNumber, String> m = new HashMap<>();
m.put(new PhoneNumber(21, 37, 3245), "xiaobai");

System.out.println(m.get(new PhoneNumber(53, 37, 3245)));//輸出:null

你可能期望輸出的是:"xiaobai",因?yàn)?code>put和get的兩個key對象的equals返回是true,但實(shí)際上得到的卻是null,為什么呢?原因就在于未覆蓋hashCode,兩個對象即便相等,但是其hashCode還是可能不等,那么put方法把PhoneNumber對象存放至一個散列桶(hash bucket)中,而get方法卻在另外一個散列桶中查找這個對象,當(dāng)然找不到,退一步說,即便是兩個實(shí)例剛好被放至于同一個散列桶中,get方法依然還是會返回null,因?yàn)镠ashMap有一項(xiàng)機(jī)制:如果兩個實(shí)例散列碼不匹配, 直接放棄比較其等同性

我想,講到這里大家應(yīng)該清楚了為什么覆蓋了equals方法的同時必須覆蓋hashCode的原因所在,但有人可能會說,我這個對象不會和基于散列的集合一起使用的,所以不需要遵守這個約定,但正所謂魔鬼隱藏在細(xì)節(jié)之中,你現(xiàn)在不會使用不代表以后不會使用(不要相信自己的記憶);你知道不能一起使用,不代表別人知道(即便有注釋別人也不一定會看)。所以建議一般情況下都遵守這項(xiàng)約定,只是稍微增加一點(diǎn)工作量而已,卻是代碼健壯的基石

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容