<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>

          【09期】說說hashCode() 和 equals() 之間的關系?

          共 7415字,需瀏覽 15分鐘

           ·

          2020-08-09 08:49

          程序員的成長之路
          互聯(lián)網(wǎng)/程序員/技術/資料共享?
          關注


          閱讀本文大概需要 6 分鐘。

          來自:java面試題精選

          上一篇關于介紹Object類下的幾種方法時面試題時,提到equals()和hashCode()方法可能引出關于“hashCode() 和 equals() 之間的關系?的面試題,本篇來解析一下這道基礎面試題。
          先祭一張圖,可以思考一下為什么?

          介紹

          equals()?的作用是用來判斷兩個對象是否相等。
          hashCode()?的作用是獲取哈希碼,也稱為散列碼;它實際上是返回一個int整數(shù)。這個哈希碼的作用是確定該對象在哈希表中的索引位置。

          關系

          我們以“類的用途”來將“hashCode() 和 equals()的關系”分2種情況來說明。

          1、不會創(chuàng)建“類對應的散列表”

          這里所說的“不會創(chuàng)建類對應的散列表”是說:我們不會在HashSet, Hashtable, HashMap等等這些本質(zhì)是散列表的數(shù)據(jù)結(jié)構(gòu)中,用到該類。例如,不會創(chuàng)建該類的HashSet集合。
          在這種情況下,該類的“hashCode() 和 equals() ”沒有半毛錢關系的!equals() 用來比較該類的兩個對象是否相等。而hashCode() 則根本沒有任何作用。
          下面,我們通過示例查看類的兩個對象相等 以及 不等時hashCode()的取值。
          import?java.util.*;
          import?java.lang.Comparable;

          /**
          ?*?@desc 比較equals()?返回true 以及?返回false時, hashCode()的值。
          ?*
          ?*/

          public?class?NormalHashCodeTest{

          ????public?static?void?main(String[]?args)?{
          ????????//?新建2個相同內(nèi)容的Person對象,
          ????????//?再用equals比較它們是否相等
          ????????Person?p1?=?new?Person("eee",?100);
          ????????Person?p2?=?new?Person("eee",?100);
          ????????Person?p3?=?new?Person("aaa",?200);
          ????????System.out.printf("p1.equals(p2)?:?%s;?p1(%d)?p2(%d)\n",?p1.equals(p2),?p1.hashCode(),?p2.hashCode());
          ????????System.out.printf("p1.equals(p3)?:?%s;?p1(%d)?p3(%d)\n",?p1.equals(p3),?p1.hashCode(),?p3.hashCode());
          ????}

          ????/**
          ?????*?@desc Person類。
          ?????*/

          ????private?static?class?Person?{
          ????????int?age;
          ????????String?name;

          ????????public?Person(String?name,?int?age)?{
          ????????????this.name?=?name;
          ????????????this.age?=?age;
          ????????}

          ????????public?String?toString()?{
          ????????????return?name?+?"?-?"?+age;
          ????????}

          ????????/**?
          ?????????*?@desc?覆蓋equals方法?
          ?????????*/
          ??
          ????????public?boolean?equals(Object?obj){??
          ????????????if(obj?==?null){??
          ????????????????return?false;??
          ????????????}??

          ????????????//如果是同一個對象返回true,反之返回false??
          ????????????if(this?==?obj){??
          ????????????????return?true;??
          ????????????}??

          ????????????//判斷是否類型相同??
          ????????????if(this.getClass()?!=?obj.getClass()){??
          ????????????????return?false;??
          ????????????}??

          ????????????Person?person?=?(Person)obj;??
          ????????????return?name.equals(person.name)?&&?age==person.age;??
          ????????}?
          ????}
          }
          運行結(jié)果:
          p1.equals(p2)?:?true;?p1(1169863946)?p2(1901116749)
          p1.equals(p3)?:?false;?p1(1169863946)?p3(2131949076)
          從結(jié)果也可以看出:p1和p2相等的情況下,hashCode()也不一定相等。

          2、會創(chuàng)建“類對應的散列表”

          這里所說的“會創(chuàng)建類對應的散列表”是說:我們會在HashSet, Hashtable, HashMap等等這些本質(zhì)是散列表的數(shù)據(jù)結(jié)構(gòu)中,用到該類。例如,會創(chuàng)建該類的HashSet集合。
          在這種情況下,該類的“hashCode() 和 equals() ”是有關系的:
          • 如果兩個對象相等,那么它們的hashCode()值一定相同。這里的相等是指,通過equals()比較兩個對象時返回true。

          • 如果兩個對象hashCode()相等,它們并不一定相等。因為在散列表中,hashCode()相等,即兩個鍵值對的哈希值相等。然而哈希值相等,并不一定能得出鍵值對相等。補充說一句:“兩個不同的鍵值對,哈希值相等”,這就是哈希沖突。

          此外,在這種情況下。若要判斷兩個對象是否相等,除了要覆蓋equals()之外,也要覆蓋hashCode()函數(shù)。否則,equals()無效。
          舉例,創(chuàng)建Person類的HashSet集合,必須同時覆蓋Person類的equals() 和 hashCode()方法。?
          如果單單只是覆蓋equals()方法。我們會發(fā)現(xiàn),equals()方法沒有達到我們想要的效果。
          import?java.util.*;
          import?java.lang.Comparable;

          /**
          ?*?@desc 比較equals()?返回true 以及?返回false時, hashCode()的值。
          ?*
          ?*/

          public?class?ConflictHashCodeTest1{

          ????public?static?void?main(String[]?args)?{
          ????????//?新建Person對象,
          ????????Person?p1?=?new?Person("eee",?100);
          ????????Person?p2?=?new?Person("eee",?100);
          ????????Person?p3?=?new?Person("aaa",?200);

          ????????//?新建HashSet對象?
          ????????HashSet?set?=?new?HashSet();
          ????????set.add(p1);
          ????????set.add(p2);
          ????????set.add(p3);

          ????????//?比較p1?和?p2,?并打印它們的hashCode()
          ????????System.out.printf("p1.equals(p2)?:?%s;?p1(%d)?p2(%d)\n",?p1.equals(p2),?p1.hashCode(),?p2.hashCode());
          ????????//?打印set
          ????????System.out.printf("set:%s\n",?set);
          ????}

          ????/**
          ?????*?@desc Person類。
          ?????*/

          ????private?static?class?Person?{
          ????????int?age;
          ????????String?name;

          ????????public?Person(String?name,?int?age)?{
          ????????????this.name?=?name;
          ????????????this.age?=?age;
          ????????}

          ????????public?String?toString()?{
          ????????????return?"("+name?+?",?"?+age+")";
          ????????}

          ????????/**?
          ?????????*?@desc?覆蓋equals方法?
          ?????????*/
          ??
          ????????@Override
          ????????public?boolean?equals(Object?obj)
          {??
          ????????????if(obj?==?null){??
          ????????????????return?false;??
          ????????????}??

          ????????????//如果是同一個對象返回true,反之返回false??
          ????????????if(this?==?obj){??
          ????????????????return?true;??
          ????????????}??

          ????????????//判斷是否類型相同??
          ????????????if(this.getClass()?!=?obj.getClass()){??
          ????????????????return?false;??
          ????????????}??

          ????????????Person?person?=?(Person)obj;??
          ????????????return?name.equals(person.name)?&&?age==person.age;??
          ????????}?
          ????}
          }
          運行結(jié)果:
          p1.equals(p2)?:?true;?p1(1169863946)?p2(1690552137)
          set:[(eee,?100),?(eee,?100),?(aaa,?200)]
          結(jié)果分析:
          我們重寫了Person的equals()。但是,很奇怪的發(fā)現(xiàn):HashSet中仍然有重復元素:p1 和 p2。為什么會出現(xiàn)這種情況呢?
          這是因為雖然p1 和 p2的內(nèi)容相等,但是它們的hashCode()不等;所以,HashSet在添加p1和p2的時候,認為它們不相等。
          那同時覆蓋equals() 和 hashCode()方法呢?
          import?java.util.*;
          import?java.lang.Comparable;

          /**
          ?*?@desc 比較equals()?返回true 以及?返回false時, hashCode()的值。
          ?*
          ?*/

          public?class?ConflictHashCodeTest2{

          ????public?static?void?main(String[]?args)?{
          ????????//?新建Person對象,
          ????????Person?p1?=?new?Person("eee",?100);
          ????????Person?p2?=?new?Person("eee",?100);
          ????????Person?p3?=?new?Person("aaa",?200);
          ????????Person?p4?=?new?Person("EEE",?100);

          ????????//?新建HashSet對象?
          ????????HashSet?set?=?new?HashSet();
          ????????set.add(p1);
          ????????set.add(p2);
          ????????set.add(p3);

          ????????//?比較p1?和?p2,?并打印它們的hashCode()
          ????????System.out.printf("p1.equals(p2)?:?%s;?p1(%d)?p2(%d)\n",?p1.equals(p2),?p1.hashCode(),?p2.hashCode());
          ????????//?比較p1?和?p4,?并打印它們的hashCode()
          ????????System.out.printf("p1.equals(p4)?:?%s;?p1(%d)?p4(%d)\n",?p1.equals(p4),?p1.hashCode(),?p4.hashCode());
          ????????//?打印set
          ????????System.out.printf("set:%s\n",?set);
          ????}

          ????/**
          ?????*?@desc Person類。
          ?????*/

          ????private?static?class?Person?{
          ????????int?age;
          ????????String?name;

          ????????public?Person(String?name,?int?age)?{
          ????????????this.name?=?name;
          ????????????this.age?=?age;
          ????????}

          ????????public?String?toString()?{
          ????????????return?name?+?"?-?"?+age;
          ????????}

          ????????/**?
          ?????????*?@desc重寫hashCode?
          ?????????*/
          ??
          ????????@Override
          ????????public?int?hashCode()
          {??
          ????????????int?nameHash?=??name.toUpperCase().hashCode();
          ????????????return?nameHash?^?age;
          ????????}

          ????????/**?
          ?????????*?@desc?覆蓋equals方法?
          ?????????*/
          ??
          ????????@Override
          ????????public?boolean?equals(Object?obj)
          {??
          ????????????if(obj?==?null){??
          ????????????????return?false;??
          ????????????}??

          ????????????//如果是同一個對象返回true,反之返回false??
          ????????????if(this?==?obj){??
          ????????????????return?true;??
          ????????????}??

          ????????????//判斷是否類型相同??
          ????????????if(this.getClass()?!=?obj.getClass()){??
          ????????????????return?false;??
          ????????????}??

          ????????????Person?person?=?(Person)obj;??
          ????????????return?name.equals(person.name)?&&?age==person.age;??
          ????????}?
          ????}
          }
          運行結(jié)果:
          p1.equals(p2)?:?true;?p1(68545)?p2(68545)
          p1.equals(p4)?:?false;?p1(68545)?p4(68545)
          set:[aaa?-?200,?eee?-?100]
          結(jié)果分析:
          這下,equals()生效了,HashSet中沒有重復元素。
          比較p1和p2,我們發(fā)現(xiàn):它們的hashCode()相等,通過equals()比較它們也返回true。所以,p1和p2被視為相等。
          比較p1和p4,我們發(fā)現(xiàn):雖然它們的hashCode()相等;但是,通過equals()比較它們返回false。所以,p1和p4被視為不相等。

          原則

          1.同一個對象(沒有發(fā)生過修改)無論何時調(diào)用hashCode()得到的返回值必須一樣。
          如果一個key對象在put的時候調(diào)用hashCode()決定了存放的位置,而在get的時候調(diào)用hashCode()得到了不一樣的返回值,這個值映射到了一個和原來不一樣的地方,那么肯定就找不到原來那個鍵值對了。
          2.hashCode()的返回值相等的對象不一定相等,通過hashCode()和equals()必須能唯一確定一個對象。不相等的對象的hashCode()的結(jié)果可以相等。hashCode()在注意關注碰撞問題的時候,也要關注生成速度問題,完美hash不現(xiàn)實。
          3.一旦重寫了equals()函數(shù)(重寫equals的時候還要注意要滿足自反性、對稱性、傳遞性、一致性),就必須重寫hashCode()函數(shù)。而且hashCode()的生成哈希值的依據(jù)應該是equals()中用來比較是否相等的字段。
          如果兩個由equals()規(guī)定相等的對象生成的hashCode不等,對于hashMap來說,他們很可能分別映射到不同位置,沒有調(diào)用equals()比較是否相等的機會,兩個實際上相等的對象可能被插入不同位置,出現(xiàn)錯誤。其他一些基于哈希方法的集合類可能也會有這個問題。

          推薦閱讀:

          畢設有著落了!一套開源的,基于SpringBoot的車牌識別系統(tǒng)

          飛天茅臺超賣事故:Redis分布式鎖請慎用!

          5T技術資源大放送!包括但不限于:C/C++,Linux,Python,Java,PHP,人工智能,單片機,樹莓派,等等。在公眾號內(nèi)回復「2048」,即可免費獲取??!

          微信掃描二維碼,關注我的公眾號

          寫留言

          朕已閱?

          瀏覽 43
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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>
                  a 视频在线观看 | 欧美成人性爱网址 | 国产一级特黄A片 | 欧美亚洲动漫 | 欧美在线伦理一 |