首页 > 解决方案 > Java 哈希码在不同机器上的工作方式不同

问题描述

我有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

问题:

这些人的哈希码在我的本地中是相同的,但是当我将此代码推广到不同的环境时,它们会导致不同的哈希码。

我无法弄清楚这个问题。所以寻求帮助!!

标签: javaspringlombok

解决方案


非常旧版本的 lombok 在哈希码算法中使用的素数略有不同;这已更改,因为知道它可能会破坏一些现有代码,原因正是@Pruthvik 在回答中所说的:您不应该依赖不同 VM 调用之间的一致哈希码。

但是,听起来您为同一个VM 调用获得了不同的哈希码,并且可能具有相同的字段 - 这不可能是由于涉及 lombok。

这一定意味着您的字段实际上并不相等。至少,lombok 通过为每个字段生成一个来生成哈希码;lombok 为您列出的所有 3 个字段生成“子”哈希码的方式都是相同的:只需hashCode()在这些对象上调用方法。所以,这些可能正在改变。

要对此进行调试,请编写一个打印出每个字段分别返回的哈希码的方法。找到它们不同的地方,你会发现不同的对象。例如,如果您当前的语言环境是土耳其语,则大写字母 I 将小写为无点 i,因此,"Jim".toLowerCase()并非"JIM".toLowerCase()在所有 VM 上都等于。这听起来像是一个合理的解释。

我不知道为什么在大火中你会把工作外包给一个包含所有东西的 apache 库,但我快速检查了文档,这个 stringutils 方法确实像听起来一样没用。它只是调用toLowerCase(). 哪个确实有这个“好吧,根据当前的语言环境”问题。试试吧lowerCase(theInput, Locale.ENGLISH),也许。

注意:您可以将字符串小写以标准化比较的理论是一种误解。它适用于英语,但不适用于许多其他语言。除非您想遵守规则“除非所有用户都说英语、荷兰语、德语、丹麦语和其他一些西方语言,否则该软件无法工作”,您可能希望减少对小写事物的依赖,然后将其用于身份识别. 那个荷兰人的事情甚至可能都行不通,他们有那个奇怪的虚线 Y 事情正在发生。(“YPENBURG”.toLowerCase() 在适当的荷兰语中可能应该是“ijpenburg”,但与土耳其语不同,我认为语言环境设置实际上不会这样做)。


推荐阅读