更改存储在基于散列的集合中的对象的hashCode

我有一个基于哈希的对象集合,例如HashSetHashMap 。 当hashCode()的实现可以随时间变化时,我可以遇到什么问题,因为它是从一些可变字段计算出来的?

它如何影响Hibernate? 是否有任何理由为什么hashCode()默认返回对象的ID是坏的? 如果重要的话,所有尚未持久化的对象都有id = 0。

Hibernate映射实体的hashCode的合理实现是什么? 一旦设置,ID就是不可变的,但是在将实体保存到数据库的时刻却不是这样。

我并不担心具有key = 0的十几个实体的HashSet性能。 我关心的是我的应用程序是否安全以及Hibernate是否使用ID作为哈希代码,因为ID在持久化时生成。

如果同一对象的哈希码随时间变化,则结果基本上是不可预测的。 散列集合使用散列码将对象分配给存储桶 – 如果散列代码突然改变,集合显然不知道,因此它可能无法找到现有对象,因为它现在散列到另一个存储桶。

返回一个对象的ID本身并不错,但是如果你提到它们中的很多都有id = 0,它会降低散列表的性能:具有相同散列码的所有对象都进入同一个桶,所以你的散列table现在并不比线性列表好。

更新:从理论上讲,只要没有其他人知道它,你的哈希码就可以改变 – 这正好暗示了@bestsss在他的评论中提到的,即从任何可能持有它的集合中删除你的对象并再次插入它哈希码已更改。 实际上,更好的选择是从对象的实际内容字段生成哈希代码,而不是依赖于数据库ID。

如果将对象添加到基于散列的集合,然后改变其状态以便更改其哈希码(并且暗示可能是.equals()调用中的行为),您可能会看到效果,包括但不限于:

  • 你放入collections品的东西似乎不再存在了
  • 获得与你所要求的不同的东西

这肯定不是你想要的。 因此,我建议仅使用不可变字段来创建哈希码。 这通常通过使字段final并在构造函数中设置它们的值来完成。

放入后不要在基于散列的集合中更改元素的哈希码。

许多程序员陷入了陷阱。 您可以认为哈希码是集合中的一种地址 ,因此在将元素放入集合后 ,您无法更改元素的地址。

Javadoc特别指出内置集合不支持这一点。 所以不要这样做。