<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 3323字,需瀏覽 7分鐘

           ·

          2022-11-18 14:05

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

          一文搞懂 == 、equals和hashCode

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

          先來看看 == 

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

          我們看看下面如下代碼:

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

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

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

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

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

          需要注意:

          因為 Java 只有值傳遞,所以,對于 == 來說,不管是比較基本數(shù)據(jù)類型,還是引用數(shù)據(jù)類型的變量,其本質(zhì)比較的都是值,只是引用類型變量存的值是對象的地址。

          來看看equals()

          equals()方法特點:

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

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

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

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

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

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

          1:類沒有重寫equals()方法:

          當(dāng)兩個對象沒有重寫equals()方法時候,通過equals()方法進行比較的時候,其實就等價于通過"=="比較兩個對象。因為在沒有重新equals方法的情況下默認都使用的是Object類的equals()方法;

          2:類重寫了equals()方法:

          一般在工作中,我們都重寫equals()方法來比較兩個對象中的屬性是否相等。如果兩個對象的屬性相等,則返回true.就認為兩個對象是相等的。


          代碼如下:

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

          測試重寫了equals()方法后,兩個girl通過equals比較:

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

          equal()方法輸入的是:true

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

          我們在Girl對象中添加地址對象屬性,在重寫equals方法:

          測試:

          結(jié)果:

          從測試效果來看,可以驗證結(jié)論:equals()比較兩個重新equals()方法對象的時候,其實就是比較的是兩個對象中每個屬性值。

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

          接下來,我們在來看看hashCode()方法

          hashcCode是什么?

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

          出處:

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

          那么為什么要有hashCode?

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

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

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

          問題:既然兩個方法都是比較對象是否相等,那么為什么JDK還要同時提供這兩個方法呢?

          答:為了提高效率。

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

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

          答:不能。因為我們知道,哈希碼是通過函數(shù)算出來的整數(shù)。既然使用的是公式,那么可能出現(xiàn)兩個對象不一樣,但是哈希碼一樣的。

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

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

          問題:如果兩個對象的hashCode值相等,它們相等嗎?

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

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

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

          2:如果兩個對象的hashCode值不相等,那么這兩個對象就不相等

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

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

          因為:4+4 = 8;4+4 = 8; 其中的8就是hashCode. 兩個算式的 a、b都是4,也是相等的。

          問題:為什么重寫equals()時候必須重寫hashCode()方法?

          因為一般在重寫equals()方法的時候,是要對兩個對象進行比較的。如果兩個對象相等的話,hashCode值必須相等,equals()方法判斷兩個對象也是相等的。

          如果重寫equals()方法時候,沒有重寫hashCode()方法的話,可能導(dǎo)致equals()方法判斷想的的兩個對象hashCCode值卻不相等。如下示例:

          我們來看看結(jié)果:

          總結(jié):

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


          思考:重寫equals()方法時候,沒有重寫hashCode()方法的haul,在使用HashMap/HashSet時候可能會出現(xiàn)什么問題?

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

          結(jié)果:

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

          其實,這就是只重寫了equals(),沒有重寫hashCode()方法的后果。

          因為在set.add()方法時候,先判斷hashcode值,從上圖我們可以看到,兩個對象hashCode值不相等。set就認為不是一個對象,所以大小就是2了。

          so,我們在重寫equals()方法的時候,一定要重寫hashCode()方法






          瀏覽 57
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产精品综合激情 | 高清无码视频网站 | 精品视频免费在线观看 | 久久五月影院 | 特黄AV|