java - 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
问题:
这些人的哈希码在我的本地中是相同的,但是当我将此代码推广到不同的环境时,它们会导致不同的哈希码。
我无法弄清楚这个问题。所以寻求帮助!!
解决方案
非常旧版本的 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”,但与土耳其语不同,我认为语言环境设置实际上不会这样做)。
推荐阅读
- c# - 如何比较对象
- java - “SQLiteDatabase.insert(TABLE_NAME,null,ContentValues);” 显示“数据类型不匹配”错误
- r - 是否可以垂直调整闪避条形图中的标签?
- python - Python中的操作顺序
- javascript - 将参数传递给函数
- reactjs - 如何将带有 styled-components 的样式应用于包装在 Material UI 网格中的组件?
- .net - 操作系统如何调用用户计划的任务来执行?
- javascript - Javascript 函数返回 undefined 即使值存在
- java - 为什么这段代码会导致堆栈溢出?为什么只需将 ==1 更改为 <2,然后它就可以工作了?
- c# - 淘汰赛 JS 选择初始值在 foreach 循环内未正确显示