1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        一文搞懂==、equals和hashCode=的區(qū)別

        共 3323字,需瀏覽 7分鐘

         ·

        2022-11-18 14:05

        面試的時(shí)候,經(jīng)常會(huì)被問(wèn)到==和equals()的區(qū)別是什么?以及我們也知道重寫(xiě)equals()時(shí)候必須重新hashCode()。這是為什么?既然有了hashCode()方法了,JDK又為什么要提供equals()方法呢?如果在重寫(xiě)equals()時(shí)候沒(méi)有重寫(xiě)hashCode(),在使用HashMap或HashSet的時(shí)候可能會(huì)出現(xiàn)什么情況?

        一文搞懂 == 、equals和hashCode

        == 和 equals()的區(qū)別是什么?

        先來(lái)看看 == 

        Java中使用==的時(shí)候,如果左右兩邊是基本類(lèi)型和兩邊是應(yīng)用類(lèi)型的作用效果是不同的:

        我們看看下面如下代碼:

        int x = 128;
        int y = 128;
        Person p = new Person(new Address("北京"));
        Person p2 = p.clone();
        System.out.println("兩個(gè)基本類(lèi)型==后值:");
        System.out.println(x==y);
        System.out.println("兩個(gè)對(duì)象(引用類(lèi)型)==后值:");
        System.out.println(p == p2);
        System.out.println(" \n p的地址值為:"+p +" \n p2的地址值為:"+p2.toString());

        輸出的結(jié)果是什么?

        從上面結(jié)果,我們可以得到如下結(jié)論:

        當(dāng) == 左右兩邊是基本類(lèi)型的時(shí)候,其實(shí)就是比較的是數(shù)值是否相等;

        當(dāng) == 左右兩邊是對(duì)象(引用)類(lèi)型的時(shí)候,其實(shí)比較的是p和p2這兩個(gè)對(duì)象所指向的堆中的對(duì)象地址,一般我們簡(jiǎn)稱(chēng):比較的是內(nèi)存地址值。

        需要注意:

        因?yàn)?Java 只有值傳遞,所以,對(duì)于 == 來(lái)說(shuō),不管是比較基本數(shù)據(jù)類(lèi)型,還是引用數(shù)據(jù)類(lèi)型的變量,其本質(zhì)比較的都是值,只是引用類(lèi)型變量存的值是對(duì)象的地址。

        來(lái)看看equals()

        equals()方法特點(diǎn):

        1:equals()方法不能用于判斷基本類(lèi)型的變量,只能用來(lái)判斷兩個(gè)對(duì)象是否相等。

        2:equals()方法存在于Object類(lèi)中的。而我們又指導(dǎo)Object類(lèi)是所有類(lèi)的直接或者間接的父類(lèi)。所以所有類(lèi)都具有equals()方法

        看看Object源碼中equals()方法:

        從源碼中我們可以看出,底層其實(shí)使用的是 == 。

        == 左右兩邊都是對(duì)象。從上面我們知道==比較對(duì)象,其實(shí)就是比較對(duì)象內(nèi)存中的地址值。

        所以,我們可以得到equals()方法存在兩種使用情況的結(jié)論:

        1:類(lèi)沒(méi)有重寫(xiě)equals()方法:

        當(dāng)兩個(gè)對(duì)象沒(méi)有重寫(xiě)equals()方法時(shí)候,通過(guò)equals()方法進(jìn)行比較的時(shí)候,其實(shí)就等價(jià)于通過(guò)"=="比較兩個(gè)對(duì)象。因?yàn)樵跊](méi)有重新equals方法的情況下默認(rèn)都使用的是Object類(lèi)的equals()方法;

        2:類(lèi)重寫(xiě)了equals()方法:

        一般在工作中,我們都重寫(xiě)equals()方法來(lái)比較兩個(gè)對(duì)象中的屬性是否相等。如果兩個(gè)對(duì)象的屬性相等,則返回true.就認(rèn)為兩個(gè)對(duì)象是相等的。


        代碼如下:

        定義一個(gè)Girl對(duì)象,有兩個(gè)屬性:樣貌和膚色。然后重寫(xiě)equals()方法

        測(cè)試重寫(xiě)了equals()方法后,兩個(gè)girl通過(guò)equals比較:

        我們來(lái)看看輸出的結(jié)果:

        equal()方法輸入的是:true

        但是實(shí)際上,兩個(gè)Girl對(duì)象在堆中的內(nèi)存地址值不一樣。

        我們?cè)贕irl對(duì)象中添加地址對(duì)象屬性,在重寫(xiě)equals方法:

        測(cè)試:

        結(jié)果:

        從測(cè)試效果來(lái)看,可以驗(yàn)證結(jié)論:equals()比較兩個(gè)重新equals()方法對(duì)象的時(shí)候,其實(shí)就是比較的是兩個(gè)對(duì)象中每個(gè)屬性值。

        現(xiàn)在再來(lái)回答 == 和 equals()方法有什么區(qū)別?這個(gè)問(wèn)題應(yīng)該好回答了吧。

        接下來(lái),我們?cè)趤?lái)看看hashCode()方法

        hashcCode是什么?

        我們?cè)谡{(diào)用對(duì)象的hashCode()方法的時(shí)候,返回的是一個(gè)int整數(shù)。這個(gè)整數(shù)其實(shí)是散列碼,不過(guò)我們習(xí)慣稱(chēng)之為哈希碼。作用就是確定這個(gè)對(duì)象在hash表中的所以位置。

        出處:

        hashCode()方法被定義在Object類(lèi)中。這也就意味著任何一個(gè)類(lèi)都有hashCode()這個(gè)方法(和equals()方法一樣,都是被定義在Object對(duì)象中)。查看Object的源碼,我們可以發(fā)現(xiàn),次方法被native關(guān)鍵字修飾的。也就是說(shuō),Object中的hashCode()方法調(diào)用的是本地方法的。其實(shí)就是調(diào)用操作系統(tǒng)自己的hashCode()方法(用C語(yǔ)言或者是C++語(yǔ)言實(shí)現(xiàn)的)。該方法通常用來(lái)將對(duì)象的內(nèi)存地址轉(zhuǎn)換成整數(shù)后返回的。

        那么為什么要有hashCode?

        起始hash存儲(chǔ)的是鍵值對(duì)(K-V)形式的,其特點(diǎn)就是:能夠根據(jù)"key"快速的檢索出對(duì)應(yīng)的"值"。在快速檢索的時(shí)候,就使用到了哈希碼。

        回想下hashMap在put對(duì)象的時(shí)候,先計(jì)算出key對(duì)應(yīng)的hashCode值,來(lái)判斷對(duì)象需要加入的位置。如果不存在,就直接插入,如果存在,就加到鏈表中。如下圖:

        從上面我們可以知道,起始 hashCode()和equals()這兩個(gè)方法都是用于比較兩個(gè)對(duì)象是否相等的。

        問(wèn)題:既然兩個(gè)方法都是比較對(duì)象是否相等,那么為什么JDK還要同時(shí)提供這兩個(gè)方法呢?

        答:為了提高效率。

        還以hashMap的put方法為例,我們知道,先計(jì)算出hashCode,如果不存在,就可以直接put了。不用比較了,少了一次比較。效率就高了。

        問(wèn)題:那么能否只使用hashCode()方法呢?

        答:不能。因?yàn)槲覀冎?,哈希碼是通過(guò)函數(shù)算出來(lái)的整數(shù)。既然使用的是公式,那么可能出現(xiàn)兩個(gè)對(duì)象不一樣,但是哈希碼一樣的。

        就比如我們使用 a+b這個(gè)公式得出的一個(gè)整數(shù)一樣。4+4 = 8;5+3=8;

        經(jīng)過(guò)公式計(jì)算的結(jié)果都是8,但是兩個(gè)算式的a和b卻是不相等的。

        問(wèn)題:如果兩個(gè)對(duì)象的hashCode值相等,它們相等嗎?

        答:不相等。如:4+4 = 8;5+3=8;

        通過(guò)上面說(shuō)明,我們可以得到hashcode相關(guān)結(jié)論:

        1:兩個(gè)對(duì)象hashcode想的,那么這兩個(gè)對(duì)象不一樣相等(hash碰撞了。如:4+4 = 8;5+3=8;)

        2:如果兩個(gè)對(duì)象的hashCode值不相等,那么這兩個(gè)對(duì)象就不相等

        通過(guò)上面我們分析equals()方法,我們還可以得到下面這個(gè)結(jié)論:

        3:如果兩個(gè)對(duì)象的hashCode想的呢并且equals()方法返回的也是true。那么我們才能認(rèn)為這兩個(gè)對(duì)象相等的。

        因?yàn)椋?+4 = 8;4+4 = 8; 其中的8就是hashCode. 兩個(gè)算式的 a、b都是4,也是相等的。

        問(wèn)題:為什么重寫(xiě)equals()時(shí)候必須重寫(xiě)hashCode()方法?

        因?yàn)橐话阍谥貙?xiě)equals()方法的時(shí)候,是要對(duì)兩個(gè)對(duì)象進(jìn)行比較的。如果兩個(gè)對(duì)象相等的話(huà),hashCode值必須相等,equals()方法判斷兩個(gè)對(duì)象也是相等的。

        如果重寫(xiě)equals()方法時(shí)候,沒(méi)有重寫(xiě)hashCode()方法的話(huà),可能導(dǎo)致equals()方法判斷想的的兩個(gè)對(duì)象hashCCode值卻不相等。如下示例:

        我們來(lái)看看結(jié)果:

        總結(jié):

        重寫(xiě)equals()方法是好,必須要重寫(xiě)hashCode()方法。


        思考:重寫(xiě)equals()方法時(shí)候,沒(méi)有重寫(xiě)hashCode()方法的haul,在使用HashMap/HashSet時(shí)候可能會(huì)出現(xiàn)什么問(wèn)題?

        我們以hashSet為例(hashSet底層使用的是hashMap來(lái)實(shí)現(xiàn)的):

        結(jié)果:

        (???(??? ;)哈? 不是說(shuō)hashSet是唯一的,不能有重復(fù)的嗎?打印出來(lái)的set集合大小是2啊,不是1啊。

        其實(shí),這就是只重寫(xiě)了equals(),沒(méi)有重寫(xiě)hashCode()方法的后果。

        因?yàn)樵趕et.add()方法時(shí)候,先判斷hashcode值,從上圖我們可以看到,兩個(gè)對(duì)象hashCode值不相等。set就認(rèn)為不是一個(gè)對(duì)象,所以大小就是2了。

        so,我們?cè)谥貙?xiě)equals()方法的時(shí)候,一定要重寫(xiě)hashCode()方法






        瀏覽 57
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            曰本一级A片 | 太粗大深好疼快拔出去软件 | 明星做爰视频免费观看 | 老司机午夜剧场 | 日本男女操逼 | 影音先锋男人的资源 | 久久精品国产AV一区二区三区 | 国产在线播精品第三 | 免费婬乱AAA大片女人 | 日韩AVAV|