Java 哈希码在不同机器上的工作方式不同
Java hash code is working differently on different machines
我有 哈希码 由 lombok 生成并将其用作标识符。逻辑如下:
@EqualsAndHashCode
@AllArgsConstructor
@Getter
public final class TestIdentifier {
private String firstName;
private String lastName;
private final LocalDate dob;
}
这是我创建对象的方式:
TestIdentifier testIdentifier = new TestIdentifier(
StringUtils.lowerCase(value.getFirstName()),
StringUtils.lowerCase(value.getLastName()),
LocalDate.ofEpochDay(
value.getDateOfBirth()));
testIdentifier.hashCode()
用例:
考虑具有以下名字/姓氏和出生日期的两个人。我希望它们的哈希值相同。
人 1:
名字姓氏 2000-08-09
人 2:
名字姓氏 2000-08-09
问题:
这些人的哈希码在我的本地中是相同的,但是当我将此代码推广到不同的环境时,它们会导致不同的哈希码。
我无法弄清楚这个问题。所以寻求帮助!!
我相信对于比较两个 TestIdentifier 对象的用例,使用 equals() 方法比较所有数据成员是更好的选择。
原因是,hashcode() 合同规定,当对象未被修改且主要用于哈希表时,在对象 returns 上调用此 method() 是相同的整数值。
java合同明确规定"This integer need not remain consistent from one execution of an application to another execution of the same application. "
如果需要阅读更多内容,请参考 Java 文档:https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode()
非常旧的 lombok 版本在 hashcode 算法中使用了略微不同的质数;这已经改变了,因为知道它可能会破坏一些现有的代码,因为@Pruthvik 在回答中说的原因:你不应该依赖不同 VM 调用之间一致的哈希码。
但是,听起来您正在为 相同 VM 调用获取不同的哈希码,可能具有相同的字段 - 这不可能是由于涉及到 lombok。
这一定意味着您的字段实际上并不相等。至少,lombok 通过为每个字段生成一个哈希码来生成哈希码; lombok 为所有 3 个列出的字段生成 'sub' 哈希码的方式完全相同:只需在这些对象上调用 hashCode()
方法。所以,这些可能正在改变。
要对此进行调试,请编写一个方法来打印出每个字段分别返回的哈希码。找到它们不同的地方,你就会发现不同的对象。例如,如果您当前的语言环境是土耳其语,则大写字母 I 会小写为无点 i,因此,"Jim".toLowerCase()
在所有 VM 上都不等于 "JIM".toLowerCase()
。这听起来像是一个合理的解释。
我不知道为什么在 blazes 中你会把工作外包给一个包含所有东西的 apache 库,但我快速检查了文档,发现这个 stringutils 方法确实像听起来一样无用。它只是调用 toLowerCase()
。确实有这个 'well, according to current locale' 问题。试试 lowerCase(theInput, Locale.ENGLISH)
,也许。
注意:可以将字符串小写以规范化比较的理论是一种误解。它适用于英语,但不适用于许多其他语言。除非您想遵守规则 'this software does not work unless all its users speak english, dutch, german, danish, and a few other western languages',否则您可能希望减少对小写事物的依赖,然后将其用于标识。那个荷兰式的东西甚至可能都行不通,他们有那个奇怪的点状 Y 东西在进行。 ("YPENBURG".toLowerCase() 在荷兰语中可能应该是 "ijpenburg",但与土耳其语不同,我认为语言环境设置实际上不会那样做)。
我有 哈希码 由 lombok 生成并将其用作标识符。逻辑如下:
@EqualsAndHashCode
@AllArgsConstructor
@Getter
public final class TestIdentifier {
private String firstName;
private String lastName;
private final LocalDate dob;
}
这是我创建对象的方式:
TestIdentifier testIdentifier = new TestIdentifier(
StringUtils.lowerCase(value.getFirstName()),
StringUtils.lowerCase(value.getLastName()),
LocalDate.ofEpochDay(
value.getDateOfBirth()));
testIdentifier.hashCode()
用例: 考虑具有以下名字/姓氏和出生日期的两个人。我希望它们的哈希值相同。
人 1:
名字姓氏 2000-08-09
人 2:
名字姓氏 2000-08-09
问题:
这些人的哈希码在我的本地中是相同的,但是当我将此代码推广到不同的环境时,它们会导致不同的哈希码。
我无法弄清楚这个问题。所以寻求帮助!!
我相信对于比较两个 TestIdentifier 对象的用例,使用 equals() 方法比较所有数据成员是更好的选择。 原因是,hashcode() 合同规定,当对象未被修改且主要用于哈希表时,在对象 returns 上调用此 method() 是相同的整数值。
java合同明确规定"This integer need not remain consistent from one execution of an application to another execution of the same application. "
如果需要阅读更多内容,请参考 Java 文档:https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode()
非常旧的 lombok 版本在 hashcode 算法中使用了略微不同的质数;这已经改变了,因为知道它可能会破坏一些现有的代码,因为@Pruthvik 在回答中说的原因:你不应该依赖不同 VM 调用之间一致的哈希码。
但是,听起来您正在为 相同 VM 调用获取不同的哈希码,可能具有相同的字段 - 这不可能是由于涉及到 lombok。
这一定意味着您的字段实际上并不相等。至少,lombok 通过为每个字段生成一个哈希码来生成哈希码; lombok 为所有 3 个列出的字段生成 'sub' 哈希码的方式完全相同:只需在这些对象上调用 hashCode()
方法。所以,这些可能正在改变。
要对此进行调试,请编写一个方法来打印出每个字段分别返回的哈希码。找到它们不同的地方,你就会发现不同的对象。例如,如果您当前的语言环境是土耳其语,则大写字母 I 会小写为无点 i,因此,"Jim".toLowerCase()
在所有 VM 上都不等于 "JIM".toLowerCase()
。这听起来像是一个合理的解释。
我不知道为什么在 blazes 中你会把工作外包给一个包含所有东西的 apache 库,但我快速检查了文档,发现这个 stringutils 方法确实像听起来一样无用。它只是调用 toLowerCase()
。确实有这个 'well, according to current locale' 问题。试试 lowerCase(theInput, Locale.ENGLISH)
,也许。
注意:可以将字符串小写以规范化比较的理论是一种误解。它适用于英语,但不适用于许多其他语言。除非您想遵守规则 'this software does not work unless all its users speak english, dutch, german, danish, and a few other western languages',否则您可能希望减少对小写事物的依赖,然后将其用于标识。那个荷兰式的东西甚至可能都行不通,他们有那个奇怪的点状 Y 东西在进行。 ("YPENBURG".toLowerCase() 在荷兰语中可能应该是 "ijpenburg",但与土耳其语不同,我认为语言环境设置实际上不会那样做)。