2017-01-31 45 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()除了斗在基于散列数据结构选择。正如你发现的那样,它肯定没有验证的地方。

相关问题