【发布时间】:2012-02-23 17:54:24
【问题描述】:
基于various bad experiences,我作为Java 程序员的经验法则是只在不可变对象上实现equals() 和hashCode(),其中对象的两个实例确实可以互换。
基本上,我想避免该链接中出现HashMap 密钥问题之类的情况,或者如下所示:
- 获取具有特定身份的东西。
- 修改它。
- 将其添加到集合中。
- (稍后)获取另一个具有相同身份的东西。
- 修改它。
- 将其添加到同一个集合中。
- 没有注意到这个添加实际上并没有发生,因为集合认为这个东西已经在那里了。
- 用集合中的东西做点什么。
- 没有注意到步骤 (5) 中的更改被忽略,我们仍然拥有步骤 (2) 中的状态。
总的来说,在我的 Java 职业生涯中,我 haven't found a lot of use 代表 equals() 除了 代表 (1) 值对象和 (2) 将事物放入集合中。我还发现不变性 + 复制和修改构造函数/构建器通常比 setter 更快乐。两个对象可能具有相同的 ID 并且可能代表相同的逻辑实体,但如果它们具有不同的数据——如果它们代表概念实体在不同时间的快照——那么它们就不是 equal()。
无论如何,我现在在一家 Hibernate 商店,我的更多精通 Hibernate 的同事告诉我这种方法行不通。具体来说,声称似乎是在以下情况下--
- Hibernate 从数据库中加载一个东西——我们称之为实例
h1。 - 这个东西被编组并通过网络服务发送到某个地方。
- Web 服务客户端对其进行修改并将修改后的版本发回。
- 修改后的版本在服务器上解组——我们将其称为实例
h4。 - 我们希望 Hibernate 使用修改来更新数据库。
-- 除非h1.equals(h4)(或者h4.equals(h1),我不清楚,但我希望它是可传递的,无论如何),Hibernate 将无法判断这些是同一件事,而且是坏事会发生的。
那么,我想知道的:
- 这是真的吗?
- 如果是这样,为什么? Hibernate 使用
equals()做什么? - 如果 Hibernate 需要
h1和h4相等,它如何(以及我们如何)跟踪哪个是修改后的版本?
注意:我已经阅读了 Hibernate 文档中的Implementing equals() and hashCode(),但它并没有解决我担心的情况,至少是直接的,也没有详细解释什么是Hibernate 确实需要equals() 和hashCode()。 equals and hashcode in Hibernate 的答案也没有,否则我不会费心发布这个。
【问题讨论】:
-
“一个比二传手更幸福的世界”:同意。在我真正需要它之前,我从不实现 setter,并争取不可变的类。
-
如果两个对象具有相同的身份和不同的数据(如您在 9 列表之后的段落中),您可能有一个错误。如果它们在不同的时间点代表同一个物体,那么它们确实是
equal(),就像10年前的我一样,即使我有不同的属性。如果在我之后将他添加到集合中,我希望旧的我取代新的我...... -
@glowcoder 如果他被添加到你之后的集合中,你会期望旧的你替换新的你,但如果你是他的
equal(),他不会。这不是哲学,这是 Java。 -
@DonRoby 不,不是。该问题的答案列出了官方的最佳实践,但没有解释幕后发生的事情或为什么这些实践是必要的。 (我还阅读了答案中链接的文档,您将在我的问题顶部看到。)