Java hashCode()在同一对象创建的不同执行中有所不同

时间:2017-01-31 10:40:06

标签: java json hashcode md5sum

基本信息: 我有一个生成MyCustomObject的MyCustomObjectGenerator。始终使用相同的值创建此对象(应该是)。这个对象包含mutch代码,接口,枚举,子类......所以我在这里保持简单。接口的所有对象或实现都覆盖等于& hashCode方法(希望以正确的方式)。

这个MyCustomObject使用自定义序列化器与Jackson序列化为JSON(MyCustomObject不包含像Jackson注释那样的任何Jackson依赖项!)。

每个JSON获取一个基于MyCustomObject的hashCode计算的ID(参见下面的代码)。此id仅用作校验和,以非常快速地识别相同的jsons。还有另一个基于UUID的ID,用于标识作业本身,因此我知道2个作业可以具有相同的校验和!

问题: 有两个JUnit-Tests(一个Junit-Testclass中的最小和最大方法),它们生成一个JSON并使用File中的预定义JSON检查此JSON。如果我运行两个测试/方法,JSON与文件中的那个匹配,但是如果我只运行testMaximal()方法,则断言失败,因为生成的id不同。所以hashCode似乎有所不同。如果我再次启动两个测试方法,jsons再次与文件中的一个匹配,因此生成的对象不包含任何随机内容,如 ZonedDateTime.now()。其他JSON值始终相同,只有ID不同。如果执行(2个方法/ 1方法)条件相同,则HashCode似乎相同,但如果更改此执行条件则不同。这对我来说真的很奇怪。

现在我必须评估,什么类没有正确覆盖(或产生不同的hashCode)hashCode方法(id基于所有包含对象的hashCodes)。有人有任何好主意通过Reflection打印MyCustomObject的每个对象,变量,子类,接口的hashCode吗?我已经尝试了

ReflectionToStringBuilder.toString(myCustomObject, ToStringStyle.DEFAULT_STYLE)

但是这不会打印myCustomObject的每个子子元素的hashCode。

如果我可以打印确切的对象值,包括。 hashValue,然后我可以比较它。

我已经找到了一个与ReflectionToStringBuilder.toString()不同的对象,但是这个对象本身包含mutch接口,变量等等,但是这个BlablaObject @ 4fb64261 [...]中的所有值都是相同的,并且hashCode缺失

最重要的问题: 是否存在已知的情况,hashCode()表现得像#34;如果你使用枚举作为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();
    }
}

2 个答案:

答案 0 :(得分:2)

hashCode()返回的值有很多类型,从一个应用程序运行到下一个应用程序运行。这包括:

  • 所有数组类型
  • 所有enum类型
  • 许多其他类型,其中对象相等和对象标识是相同的;例如Object,,线程, StringBuilder / StringBuffer`。

作为一般规则,如果由Java SE定义的类不是记录,因为它具有与equals语义不同的Object.equals(Object)方法,那么您应该假设它也使用Object.hashCode() ...并且哈希码在一次运行之间会有所不同。

答案 1 :(得分:1)

除了基于散列的数据结构中的存储桶选择之外,您不应该使用hashCode()。正如你所发现的那样,它肯定没有在验证中占有一席之地。