Sparta Yew

               簡(jiǎn)約、職業(yè)、恒久
          隨筆 - 15, 文章 - 1, 評(píng)論 - 276, 引用 - 0
          數(shù)據(jù)加載中……

          hibernate中提倡持久類實(shí)現(xiàn)equals()和hashCode()的原因分析


          sparta-紫杉  11/4/21  17:18


              讀《Hibernate3.0.2完整中文教程》中的“5.5 實(shí)現(xiàn)equals()和hashCode()”一文,在本文中強(qiáng)調(diào),當(dāng)對(duì)于多表關(guān)聯(lián)的數(shù)據(jù)進(jìn)行操作時(shí),尤其想把持久類的實(shí)例放入Set時(shí)(在Hibernate中這種操作尤其常見),或者想重用脫管實(shí)例時(shí),均需要對(duì)equals()和hashCode()方法進(jìn)行重寫。

              原因是由于在Hibernate中,需要保證持久化標(biāo)識(shí)(數(shù)據(jù)庫的行)和僅在特定會(huì)話范圍內(nèi)的Java標(biāo)識(shí)是等值的。我們必然希望Set有明確的語義,以避免混合了來自不同會(huì)話中獲取的實(shí)例,從而確保數(shù)據(jù)的持久化不會(huì)發(fā)生錯(cuò)誤。

              若使用過Set,你會(huì)知道Set中是不允許存儲(chǔ)重復(fù)值的,這也是為什么Hibernate推薦在多表關(guān)聯(lián)的映射中采用Set作為存儲(chǔ)實(shí)體對(duì)象的主要原因。在多表關(guān)聯(lián)映射中的持久類中,常見如下代碼:

              private Set<?> sysUsersRoles = new HashSet(0);
              
          private Set<?> sysRolesAuthorities = new HashSet(0);

              
          public Set getSysUsersRoles() {
                  
          return this.sysUsersRoles;
              }


              
          public void setSysUsersRoles(Set sysUsersRoles) {
                  
          this.sysUsersRoles = sysUsersRoles;
              }


              
          public Set getSysRolesAuthorities() {
                  
          return this.sysRolesAuthorities;
              }


              
          public void setSysRolesAuthorities(Set sysRolesAuthorities) {
                  
          this.sysRolesAuthorities = sysRolesAuthorities;
              }

              
              按照Hibernate的提倡,應(yīng)該在該持久化類里,重寫equals()和hashCode()方法。那么為什么要對(duì)這兩個(gè)方法進(jìn)行重寫呢? Set里面不是不允許有重復(fù)的值嗎?
          重寫這兩個(gè)方法究竟能起到什么作用?equals()和hashCode()的意義究竟是什么?

          這是我看到Hibernate提倡的重寫這兩個(gè)方法之后我的疑問!

          不妨先來探討一下equals()和hashCode()的作用吧。

          實(shí)際上,equals()和hashCode()這兩個(gè)方法存在的意義是為了區(qū)別對(duì)象。這兩個(gè)方法均來自于Object類。

          在對(duì)象運(yùn)行期間,為了在運(yùn)行期區(qū)別各對(duì)象,就是通過這兩個(gè)方法,它們之間的區(qū)別如下:

          1.Object類的public boolean equals(Object obj)方法是通過 return this == obj;這種方式比較兩個(gè)對(duì)象是否相同。這里比較的是引用。
          2.Object類的public int hashCode()方法,是通過該實(shí)例地址轉(zhuǎn)換為int值。所以不同的Object實(shí)例在同一運(yùn)行期hashCode一定不相同。

          現(xiàn)在解決了equals()和hashCode()是什么以及什么作用的問題。

          那么再來談?wù)凥ibernate的運(yùn)行機(jī)理吧:
              在Hibernate的運(yùn)行期內(nèi),通過find或者其他方式提取的對(duì)象列表,在不同上下文的操作中,或者在瞬時(shí)、持久、脫管三種狀態(tài)的變換中,為了避免類名相同,但對(duì)象內(nèi)容不同的實(shí)例互相碰撞造成混亂,就需要采用更加準(zhǔn)確的區(qū)別對(duì)象的方法,而此時(shí)的equals()和hashCode()已經(jīng)不能滿足要求,只有對(duì)這兩個(gè)方法進(jìn)行重寫,增加對(duì)這些持久類的各屬性的內(nèi)容進(jìn)行區(qū)分,才能真正區(qū)分從Hibernate的find方法中提取的對(duì)象。

          那么什么樣的實(shí)例才算是相同的呢? 當(dāng)然除了你的持久類名標(biāo)識(shí)之外,還需要明確的標(biāo)識(shí)出持久化實(shí)例中某些屬性的值也是相等的,兩個(gè)實(shí)例才算是真正相同。

          比如以下兩行數(shù)據(jù)來自于Person表(字段內(nèi)容包括ID,姓名name,年齡age,父親姓名fartherName),這是實(shí)例相同的例證:

          1,王長(zhǎng)江,30,王有才;
          1,王長(zhǎng)江,30,王有才;

          以下兩行實(shí)例是不相同的例證:
          1,王長(zhǎng)江,30,王有才;
          1,王長(zhǎng)江,30,王有財(cái);

          哈哈,看出區(qū)別來了嗎? 只有一字只差,就會(huì)在Hibernate管理的實(shí)例中被看作兩個(gè)實(shí)例,這就是你重寫hashCode()的重要作用。

          順便將重寫的hashCode()和equals()也寫在下面吧:

          public boolean equals( Object other ){
                  
                  
          ifthis == other ) return true;
                  
                  
          if!( other instanceof Person ) ) return false;
                  
                  
          final Person person = (Person)other;
                  
                  
          if!person.getName().equals( getName() ) ) return false;
                  
                  
          if!person.getAge().equals( getAge())) return false;

                  
          if!person.getFartherName().equals( getFartherName())) return false;
                  
                  
          return true;
                  
              }

              
              
          public int hashCode(){
                  
          int result;
                  
                  result 
          = getName().hashCode();
                  
                  result 
          = 29 * result + getAge();

                  result 
          = 29 * result + getFartherName();
                  
                  
          return result;
          }


          還有,朋友們也可以鍵入以下代碼嘗試一下兩者的區(qū)別:

          public static void main(String[] args){
                  
                  SysRoles role1 
          = new SysRoles("1","lxb","ljh");
                  SysRoles role2 
          = new SysRoles("1","lxb","ljh");
                  
                  
          /*
                   * 經(jīng)過試驗(yàn),當(dāng)不重寫equals和hashCode時(shí)顯示為false;
                   * 重寫時(shí),顯示為true。
                   * 這就是為什么重寫equals和hashCode的原因,當(dāng)你希望從hiberate中提取的對(duì)象實(shí)例中,
                   * 若是所有字段的內(nèi)容都相同,就認(rèn)為這兩個(gè)對(duì)象實(shí)例是相同的,此時(shí)就需要重寫equals和hashCode。
                   * 重寫equals和hashCode意味著,混雜在不同上下文及Session中的兩個(gè)實(shí)例對(duì)象有了確定的語義。
                   
          */

                  System.out.println(role1.equals(role2));
                  
                  
          /*
                   * 經(jīng)過試驗(yàn),當(dāng)不重寫equals和hashCode時(shí)顯示為false;
                   * 重寫時(shí),顯示為true。
                   * 
                   
          */

                  System.out.println(role1.hashCode() 
          == role2.hashCode());
                  
          }

              
              哈哈,朋友們自己總結(jié)一下吧!



                      -東營(yíng) sparta-紫杉 原創(chuàng),轉(zhuǎn)載請(qǐng)注明出處 :)
                      http://www.aygfsteel.com/SpartaYew/
                      SpartaYew@163.com
           
                      
          QQ:22086526

          posted on 2011-05-19 10:40 sparta-紫杉 閱讀(3190) 評(píng)論(1)  編輯  收藏 所屬分類: SSH2

          評(píng)論

          # re: hibernate中提倡持久類實(shí)現(xiàn)equals()和hashCode()的原因分析  回復(fù)  更多評(píng)論   

          謝謝,大概看明白了一點(diǎn)點(diǎn),我再看看。
          2014-09-15 11:17 | 小星星
          主站蜘蛛池模板: 南江县| 白沙| 武宁县| 织金县| 祥云县| 喀喇沁旗| 博罗县| 突泉县| 龙州县| 自贡市| 巴楚县| 陇南市| 邢台县| 阿合奇县| 镶黄旗| 临夏市| 安乡县| 嘉祥县| 金山区| 东台市| 土默特右旗| 马尔康县| 德州市| 临猗县| 普宁市| 苏尼特右旗| 邯郸市| 东莞市| 泽普县| 岢岚县| 嘉祥县| 高清| 蒙山县| 志丹县| 通化市| 泉州市| 巩义市| 东兴市| 巴塘县| 怀集县| 建始县|