溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

為什么要重寫(xiě)hashCode和equals方法

發(fā)布時(shí)間:2021-11-12 16:44:42 來(lái)源:億速云 閱讀:197 作者:柒染 欄目:大數(shù)據(jù)

這篇文章將為大家詳細(xì)講解有關(guān)為什么要重寫(xiě)hashCode和equals方法,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。

如果不被重寫(xiě)(原生)的hashCode和equals是什么樣的?

  1.       不被重寫(xiě)(原生)的hashCode值是根據(jù)內(nèi)存地址換算出來(lái)的一個(gè)值。

  2.       不被重寫(xiě)(原生)的equals方法是嚴(yán)格判斷一個(gè)對(duì)象是否相等的方法(object1 == object2)。

  3. 為什么要重寫(xiě)hashCode和equals方法

  4. //JAVA代碼:    public static void main(String[] args) {
            Object obj1 = new Object();
            Object obj2 = new Object();
            Object obj3 = obj2;
            System.out.println("obj1 equals obj2 ?" + obj1.equals(obj2));
            System.out.println("obj2 equals obj3 ?" + obj2.equals(obj3));
            System.out.println("obj1's hashcode: " + obj1.hashCode());
            System.out.println("obj2's hashcode: " + obj2.hashCode());
            System.out.println("obj2's hashcode: " + obj3.hashCode());
        }
    }//輸出結(jié)果:obj1==obj2 ?false obj2==obj3 ?true obj1's hashcode: 12677476 
    obj2's hashcode: 33263331 
    obj3's hashcode: 33263331


  為什么需要重寫(xiě)equals和hashCode方法?

 如果沒(méi)有重寫(xiě)hashCode和equals方法,比較的是地址值。因?yàn)镺bject的equals方法中使用是==。

為什么要重寫(xiě)hashCode和equals方法
      在我們的業(yè)務(wù)系統(tǒng)中判斷對(duì)象時(shí)有時(shí)候需要的不是一種嚴(yán)格意義上的相等,而是一種業(yè)務(wù)上的對(duì)象相等。在這種情況下,原生的equals方法就不能滿足我們的需求了
      所以這個(gè)時(shí)候我們需要重寫(xiě)equals方法,來(lái)滿足我們的業(yè)務(wù)系統(tǒng)上的需求。那么為什么在重寫(xiě)equals方法的時(shí)候需要重寫(xiě)hashCode方法呢?
      我們先來(lái)看一下Object.hashCode的通用約定

  1.     在一個(gè)應(yīng)用程序執(zhí)行期間,如果一個(gè)對(duì)象的equals方法做比較所用到的信息沒(méi)有被修改的話,那么,對(duì)該對(duì)象調(diào)用hashCode方法多次,它必須始終如一地返回 同一個(gè)整數(shù)。在同一個(gè)應(yīng)用程序的多次執(zhí)行過(guò)程中,這個(gè)整數(shù)可以不同,即這個(gè)應(yīng)用程序這次執(zhí)行返回的整數(shù)與下一次執(zhí)行返回的整數(shù)可以不一致。

  2.     如果兩個(gè)對(duì)象根據(jù)equals(Object)方法是相等的,那么調(diào)用這兩個(gè)對(duì)象中任一個(gè)對(duì)象的hashCode方法必須產(chǎn)生同樣的整數(shù)結(jié)果。

  3.   如果兩個(gè)對(duì)象根據(jù)equals(Object)方法是不相等的,那么調(diào)用這兩個(gè)對(duì)象中任一個(gè)對(duì)象的hashCode方法,不要求必須產(chǎn)生不同的整數(shù)結(jié)果。然而,程序員應(yīng)該意識(shí)到這樣的事實(shí),對(duì)于不相等的對(duì)象產(chǎn)生截然不同的整數(shù)結(jié)果,有可能提高散列表(hash table)的性能。

     如果只重寫(xiě)了equals方法而沒(méi)有重寫(xiě)hashCode方法的話,則會(huì)違反約定的第二條:相等的對(duì)象必須具有相等的散列碼(hashCode)
     同時(shí)對(duì)于HashSet和HashMap這些基于散列值(hash)實(shí)現(xiàn)的類。
HashMap的底層處理機(jī)制是以數(shù)組的方法保存放入的數(shù)據(jù)的(Node<K,V>[] table),其中的關(guān)鍵是數(shù)組下標(biāo)的處理。數(shù)組的下標(biāo)是根據(jù)傳入的元素hashCode方法的返回值再和特定的值異或決定的。

如果該數(shù)組位置上已經(jīng)有放入的值了,且傳入的鍵值相等則不處理,若不相等則覆蓋原來(lái)的值,如果數(shù)組位置沒(méi)有條目,則插入,并加入到相應(yīng)的鏈表中。檢查鍵是否存在也是根據(jù)hashCode值來(lái)確定的。所以如果不重寫(xiě)hashCode的話,可能導(dǎo)致HashSet、HashMap不能正常的運(yùn)作、
  如果我們將某個(gè)自定義對(duì)象存到HashMap或者HashSet及其類似實(shí)現(xiàn)類中的時(shí)候,如果該對(duì)象的屬性參與了hashCode的計(jì)算,那么就不能修改該對(duì)象參數(shù)hashCode計(jì)算的屬性了。有可能會(huì)移除不了元素,導(dǎo)致內(nèi)存泄漏。

擴(kuò)展:
      在重寫(xiě)equals方法的時(shí)候,需要遵守下面的通用約定:
           1、自反性。
               對(duì)于任意的引用值x,x.equals(x)一定為true。
           2、對(duì)稱性。
               對(duì)于任意的引用值x和y,當(dāng)且僅當(dāng)y.equals(x)返回true時(shí),x.equals(y)也一定返回true。
           3、傳遞性。
               對(duì)于任意的引用值x、y和z,如果x.equals(y)返回true,并且y.equals(z)也返回true,那么x.equals(z)也一定返回true。
           4、一致性。
               對(duì)于任意的引用值x和y,如果用于equals比較的對(duì)象沒(méi)有被修改的話,那么,對(duì)此調(diào)用x.equals(y)要么一致地返回true,要么一致的返回false。
           5、對(duì)于任意的非空引用值x,x.equals(null)一定返回false。
     重寫(xiě)hashCode方法的大致方式:
            a、把某個(gè)非零常數(shù)值,比如說(shuō)17(最好是素?cái)?shù)),保存在一個(gè)叫result的int類型的變量中。
            b、對(duì)于對(duì)象中每一個(gè)關(guān)鍵域f(值equals方法中考慮的每一個(gè)域),完成一些步驟:
                1、為該域計(jì)算int類型的散列嗎c:
                    1)、如果該域是boolean類型,則計(jì)算(f?0:1)。
                    2)、如果該域是byte、char、short或者int類型,則計(jì)算(int)f。
                    3)、如果該域是float類型,則計(jì)算Float.floatToIntBits(f)。
                    4)、如果該域是long類型,則計(jì)算(int)(f ^ (f>>>32))。
                    5)、如果該域是double類型,則計(jì)算Double.doubleToLongBits(f)得到一個(gè)long類型的值,然后按照步驟4,對(duì)該long型值計(jì)算散列值。
6)、如果該域是一個(gè)對(duì)象引用,并且該類的equals方法通過(guò)遞歸調(diào)用equals的方式來(lái)比較這個(gè)域,則同樣對(duì)這個(gè)域遞歸調(diào)用hashCode。如果要求一個(gè)更為復(fù)雜的比較,則為這個(gè)域計(jì)算一個(gè)“規(guī)范表示”,然后針對(duì)這個(gè)范式表示調(diào)用hashCode。如果這個(gè)域的值為null,則返回0(或者其他某個(gè)常數(shù))
                    7)、如果該域是一個(gè)數(shù)組,則把每一個(gè)元素當(dāng)做單獨(dú)的域來(lái)處理。也就是說(shuō),遞歸地應(yīng)用上述規(guī)則,對(duì)每個(gè)重要的元素計(jì)算一個(gè)散列碼,然后根據(jù)步驟下面的做法把這些散列值組合起來(lái)。
                2、按照下面的公式,把步驟1中計(jì)算得到的散列碼C組合到result中:
                    result = 31*result+c。
            c、返回result。
            d、寫(xiě)完hashCode方法之后,問(wèn)自己“是否相等的實(shí)例具有相等的散列碼”。如果不是的話,找出原因,并修改。

關(guān)于為什么要重寫(xiě)hashCode和equals方法就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI