Sparta Yew

               簡約、職業、恒久
          隨筆 - 15, 文章 - 1, 評論 - 276, 引用 - 0
          數據加載中……

          hibernate中提倡持久類實現equals()和hashCode()的原因分析


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


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

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

              若使用過Set,你會知道Set中是不允許存儲重復值的,這也是為什么Hibernate推薦在多表關聯的映射中采用Set作為存儲實體對象的主要原因。在多表關聯映射中的持久類中,常見如下代碼:

              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的提倡,應該在該持久化類里,重寫equals()和hashCode()方法。那么為什么要對這兩個方法進行重寫呢? Set里面不是不允許有重復的值嗎?
          重寫這兩個方法究竟能起到什么作用?equals()和hashCode()的意義究竟是什么?

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

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

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

          在對象運行期間,為了在運行期區別各對象,就是通過這兩個方法,它們之間的區別如下:

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

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

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

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

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

          1,王長江,30,王有才;
          1,王長江,30,王有才;

          以下兩行實例是不相同的例證:
          1,王長江,30,王有才;
          1,王長江,30,王有財;

          哈哈,看出區別來了嗎? 只有一字只差,就會在Hibernate管理的實例中被看作兩個實例,這就是你重寫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;
          }


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

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

                  System.out.println(role1.equals(role2));
                  
                  
          /*
                   * 經過試驗,當不重寫equals和hashCode時顯示為false;
                   * 重寫時,顯示為true。
                   * 
                   
          */

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

              
              哈哈,朋友們自己總結一下吧!



                      -東營 sparta-紫杉 原創,轉載請注明出處 :)
                      http://www.aygfsteel.com/SpartaYew/
                      SpartaYew@163.com
           
                      
          QQ:22086526

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

          評論

          # re: hibernate中提倡持久類實現equals()和hashCode()的原因分析  回復  更多評論   

          謝謝,大概看明白了一點點,我再看看。
          2014-09-15 11:17 | 小星星
          主站蜘蛛池模板: 郯城县| 万宁市| 龙海市| 韩城市| 湘西| 华蓥市| 虹口区| 霸州市| 偃师市| 个旧市| 辽中县| 宜丰县| 岳阳县| 且末县| 保定市| 沾化县| 新邵县| 米林县| 西乡县| 高邑县| 阿克苏市| 绍兴市| 徐水县| 安顺市| 金沙县| 河池市| 广丰县| 开鲁县| 西乌| 增城市| 依兰县| 乐都县| 新郑市| 同德县| 万年县| 盈江县| 中西区| 马尔康县| 绥棱县| 唐河县| 镇坪县|