2017-01-31 63 views
0

基本信息: 我有一個MyCustomObjectGenerator,它生成MyCustomObject。該對象(應該)始終使用相同的值創建。這個對象包含mutch代碼,接口,枚舉,子類......,所以我在這裏簡單說明。接口的所有對象或實現都會覆蓋equals & hashCode方法(希望以正確的方式)。Java hashCode()在創建相同對象的不同執行方面有所不同

這個MyCustomObject被序列化爲帶有自定義序列化器的Jackson的JSON(MyCustomObject不包含任何傑克遜依賴項,比如Jackson註釋!)。

每個JSON都會根據MyCustomObject的hashCode獲取一個ID(請參閱下面的代碼)。這個ID只是作爲校驗和來快速識別相同的jsons。還有另一個基於UUID的ID,用於標識作業本身,所以我知道2個作業可以具有相同的校驗和!

問題: 有兩種基於JUnit測試(在一個Junit的-識別TestClass最小&最大法),即產生JSON,並檢查此JSON與來自文件的預定JSON。如果我運行這兩個測試/方法,JSON與文件中的JSON匹配,但是如果我只是運行testMaximal()方法,斷言失敗,因爲生成的ID不相同。所以hashCode似乎有所不同。如果我再次啓動兩個測試方法,jsons再次與文件中的那個匹配,所以生成的對象不包含任何隨機內容,如ZonedDateTime.now()。其他JSON值始終相同,只有ID不同。如果執行(2個方法/ 1個方法)條件相同,則HashCode似乎相同,但如果此執行條件發生更改,則HashCode會有所不同。這對我來說真的很奇怪。

現在我必須評估什麼類不能正確覆蓋(或產生不同的hashCode)hashCode方法(id是基於所有包含對象的hashCodes)。是否有人有任何好主意通過反射來打印MyCustomObject的每個對象,變量,子類,接口的hashCode?我已經試過

ReflectionToStringBuilder.toString(myCustomObject, ToStringStyle.DEFAULT_STYLE) 

但是這不會打印myCustomObject的每個子子元素的hashCode。

如果我可以打印確切的對象值incl。 hashValue,然後我可以比較它。

我已經找到一個與ReflectionToStringBuilder.toString()不同的對象,但是這個對象本身包含了mutch接口,變量等等,但是這個BlablaObject @ 4fb64261 [...]中的所有值都是相同的,哈希碼缺少

在頂部問題: 是否有已知的情況下,這hashCode()方法的行爲古怪,如「如果你在一個HashMap使用枚舉爲重點,然後的hashCode依賴於Java堆棧或JVM版本」心嚮往之。像那樣。


CODE

MyCustomObjectGenerator的.java

public class MyCustomObjectGenerator { 

    private MyCustomObject(){}; 

    public static MyCustomObject generate(boolean isMinimal){ 
     //if minimal then create minimal object 
     //if minimal == false then create maximized object**strong text** 
     MyCustomObject myCustomObject = new MyCustomObject(...); 
     myCustomObject.setXY(...) 
     ... 
     return myCustomObject; 
    } 
} 

MyCustomObject。java的

import javax.xml.bind.DatatypeConverter; 
import java.io.UnsupportedEncodingException; 
import java.security.MessageDigest; 
import java.security.NoSuchAlgorithmException; 
import org.apache.commons.lang3.builder.HashCodeBuilder; 
import org.apache.commons.lang3.builder.EqualsBuilder; 

public class MyCustomObject { 
    //variables, enums, interface ... here 
    ...  
    public MyCustomObject(...){...} 

    //mutch code here 
    ... 

    public String getChecksum() { 
     String id = Integer.toString(hashCode()); 
     try { 
      MessageDigest md = MessageDigest.getInstance("MD5"); 
      byte[] digest = md.digest(id.getBytes("UTF-8")); 
      id = DatatypeConverter.printHexBinary(digest); 
     } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) { 
      // do nothing here 
     } 
     return new id; 
    } 

    @Override 
    public int hashCode() { 
     return new HashCodeBuilder(-1013166723, 372138085) 
     //if needed in extended classes: .appendSuper(super.hashCode()) 
     .append(...) 
     .... 
     .toHashCode(); 
    } 

    @Override 
    public boolean equals(
      final Object other) { 
     if (!(other instanceof MyCustomObject)) { 
      return false; 
     } 
     MyCustomObject castOther = (MyCustomObject) other; 
     return new EqualsBuilder() 
      // if needed in extended classes: .appendSuper(super.hashCode()) 
      .append(..., ...) 
      .... 
      .isEquals(); 
    } 
} 
+1

Enum默認的hashCode()被定義爲super.hashCode()(java.lang.Object的實現),因此每個JVM實例都有一個不同。 HashCode合同規定:「從應用程序的一次執行到同一應用程序的另一次執行,此整數不必保持一致。」所以我想你有它:要麼覆蓋每個hashCode()方法,即使對於枚舉,也要確保其跨JVM實例的穩定性,否則每個實例的散列值都會有所不同。 – GPI

回答

2

有很多類型,其中hashCode()返回的值會因應用程序運行而異。這包括:

  • 所有數組類型
  • 所有enum類型
  • 許多其他類型的,其中對象的相等和對象身份是相同的東西;例如Object,,線程, StringBuilder / StringBuffer`。

作爲一般規則,如果由Java SE的定義爲一類不是記錄爲具有equals方法,在從Object.equals(Object)語義不同,那麼你就應該認爲它也使用Object.hashCode() ...那從一次運行到下一次運行,這些哈希碼都會有所不同。

1

你不應該使用hashCode()除了鬥在基於散列數據結構選擇。正如你發現的那樣,它肯定沒有驗證的地方。

相關問題