Java hashCode() 在同一对象创建的不同执行中不同
Java hashCode() differs in different executions of same object creation
基本信息:
我有一个生成 MyCustomObject 的 MyCustomObjectGenerator 。该对象(应该是)始终使用相同的值创建。这个对象包含 mutch 代码、接口、枚举、sub-classes ...,所以我在这里保持简单。接口的所有对象或实现都会覆盖 equals 和 hashCode 方法(希望以正确的方式)。
此 MyCustomObject 使用带有自定义序列化程序的 Jackson 序列化为 JSON(MyCustomObject 不包含任何 Jackson 依赖项,如 Jackson 注释!)。
每个 JSON 得到一个根据 MyCustomObject 的 hashCode 计算的 ID(见下面的代码)。此 id 仅用作校验和以非常快速地识别相同的 json。还有另一个基于 UUID 的 ID,它标识作业本身,所以我知道 2 个作业可以具有相同的校验和!
问题:
有两个 JUnit 测试(一个 Junit 测试 class 中的最小和最大方法),生成一个 JSON 并使用文件中预定义的 JSON 检查此 JSON。如果我 运行 tests/methods 和 JSON 都与文件中的匹配,但是如果我只是 运行 testMaximal() 方法断言失败,因为生成的 id 不一样。所以 hashCode 似乎有所不同。如果我再次启动这两种测试方法,jsons 将再次与来自 file 的方法匹配,因此生成的对象不包含任何随机内容,如 ZonedDateTime.now()。其他 JSON 值始终相同,只是 ID 不同。如果执行(2 methods/1 方法)条件相同,则HashCode 似乎相同,但如果更改此执行条件,则HashCode 不同。这对我来说真的很奇怪。
现在我必须评估,class 没有正确覆盖(或产生不同的 hashCode)hashCode 方法(id 基于所有包含对象的 hashCode)。有人有什么好主意通过反射打印 MyCustomObject 的每个对象、变量、subclass、接口...的 hashCode 吗?我已经试过了
ReflectionToStringBuilder.toString(myCustomObject, ToStringStyle.DEFAULT_STYLE)
但这不会打印 myCustomObject 的每个子元素的 hashCode。
如果我可以打印出准确的对象值,包括。 hashValue,然后我可以比较它。
我已经找到了一个与ReflectionToStringBuilder.toString()不同的对象,但是这个对象本身包含mutch接口,变量等等,但是这个BlablaObject@4fb64261[...]中的所有值都是相同的,并且缺少 hashCode
关于第一个问题:
是否存在已知的情况,即 hashCode() 表现得像 "If you use enum as key in a HashMap, then hashCode depends on java stack or JVM version" 或 sth 一样奇怪。就这样。
代码
我的自定义对象生成器。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();
}
}
除了在基于散列的数据结构中选择存储桶外,您不应该使用 hashCode()
。正如您所发现的,它在验证中肯定没有立足之地。
在许多类型中,hashCode()
返回的值会因一个应用程序 运行 下一个应用程序而异。这包括:
- 所有数组类型
- 所有
enum
类型
- 对象相等性和对象标识相同的许多其他类型;例如
Object
、Class
、Thread
、StringBuilder
和 StringBuffer
.
作为一般规则,如果由 Java SE 定义的 class 没有 记录 具有不同的 equals
方法在来自 Object.equals(Object)
的语义中,那么你应该假设它也使用 Object.hashCode()
...并且哈希码会从一个 运行 到下一个
基本信息: 我有一个生成 MyCustomObject 的 MyCustomObjectGenerator 。该对象(应该是)始终使用相同的值创建。这个对象包含 mutch 代码、接口、枚举、sub-classes ...,所以我在这里保持简单。接口的所有对象或实现都会覆盖 equals 和 hashCode 方法(希望以正确的方式)。
此 MyCustomObject 使用带有自定义序列化程序的 Jackson 序列化为 JSON(MyCustomObject 不包含任何 Jackson 依赖项,如 Jackson 注释!)。
每个 JSON 得到一个根据 MyCustomObject 的 hashCode 计算的 ID(见下面的代码)。此 id 仅用作校验和以非常快速地识别相同的 json。还有另一个基于 UUID 的 ID,它标识作业本身,所以我知道 2 个作业可以具有相同的校验和!
问题: 有两个 JUnit 测试(一个 Junit 测试 class 中的最小和最大方法),生成一个 JSON 并使用文件中预定义的 JSON 检查此 JSON。如果我 运行 tests/methods 和 JSON 都与文件中的匹配,但是如果我只是 运行 testMaximal() 方法断言失败,因为生成的 id 不一样。所以 hashCode 似乎有所不同。如果我再次启动这两种测试方法,jsons 将再次与来自 file 的方法匹配,因此生成的对象不包含任何随机内容,如 ZonedDateTime.now()。其他 JSON 值始终相同,只是 ID 不同。如果执行(2 methods/1 方法)条件相同,则HashCode 似乎相同,但如果更改此执行条件,则HashCode 不同。这对我来说真的很奇怪。
现在我必须评估,class 没有正确覆盖(或产生不同的 hashCode)hashCode 方法(id 基于所有包含对象的 hashCode)。有人有什么好主意通过反射打印 MyCustomObject 的每个对象、变量、subclass、接口...的 hashCode 吗?我已经试过了
ReflectionToStringBuilder.toString(myCustomObject, ToStringStyle.DEFAULT_STYLE)
但这不会打印 myCustomObject 的每个子元素的 hashCode。
如果我可以打印出准确的对象值,包括。 hashValue,然后我可以比较它。
我已经找到了一个与ReflectionToStringBuilder.toString()不同的对象,但是这个对象本身包含mutch接口,变量等等,但是这个BlablaObject@4fb64261[...]中的所有值都是相同的,并且缺少 hashCode
关于第一个问题: 是否存在已知的情况,即 hashCode() 表现得像 "If you use enum as key in a HashMap, then hashCode depends on java stack or JVM version" 或 sth 一样奇怪。就这样。
代码
我的自定义对象生成器。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();
}
}
除了在基于散列的数据结构中选择存储桶外,您不应该使用 hashCode()
。正如您所发现的,它在验证中肯定没有立足之地。
在许多类型中,hashCode()
返回的值会因一个应用程序 运行 下一个应用程序而异。这包括:
- 所有数组类型
- 所有
enum
类型 - 对象相等性和对象标识相同的许多其他类型;例如
Object
、Class
、Thread
、StringBuilder
和StringBuffer
.
作为一般规则,如果由 Java SE 定义的 class 没有 记录 具有不同的 equals
方法在来自 Object.equals(Object)
的语义中,那么你应该假设它也使用 Object.hashCode()
...并且哈希码会从一个 运行 到下一个