5

这是我在java(1.6)中看到的最疯狂的事情:

Set<ActionPlan> actionPlans = assessment.getActionPlans();
//getActionPlans() returns a java.util.HashSet<ActionPlan>
ActionPlan actionPlan = actionPlans.iterator().next();
assertTrue(actionPlan1.equals(actionPlan));
assertEquals(actionPlan1.hashCode(), actionPlan.hashCode());
assertTrue(actionPlans.contains(actionPlan1));

前两个断言通过,但最后一个失败。

我不会向您提供有关 ActionPlan 和 Assessment 课程的详细信息,因为这无关紧要。contains 方法在 equals 和 hash 没有的地方失败。

我并不是说 java 坏了或其他什么,我的代码中可能发生了一些有趣的事情。

请注意,我是一位经验丰富的 java 程序员,我知道 dos 并且不知道实现 equals 和 hashCode。因此,如果我的代码中缺少某些内容,那并不是很明显。

有没有人见过如此令人费解的事情?

编辑

我对我的代码进行了一些研究,现在我认为问题出在休眠状态。我已经记录了 ActionPlan 对象的 hashCode,在创建之后以及代码的不同部分,直到调用失败的断言。它没有改变

我还检查了由assessment.getActionPlans() 返回的类,它是:

org.hibernate.collection.internal.PersistentSet

我很想相信 Set 的这个实现没有正确使用 equals 或 hashcode。

有没有人对此有见识?

4

3 回答 3

15

有可能的解释

  • 您有一个不使用 equals 或 hashCode 的排序集。
  • 你有“覆盖” equals(MyClass) 而不是 equals(Object)
  • hashCode 使用的字段已更改。这会使 Set 处于不可用的状态。

测试最后一种可能性的最简单方法是尝试

assertTrue(new HashSet(actionPlans).contains(actionPlan1));

我怀疑这会在你的情况下通过。;)


Date 有一个缺陷,它是可变的,而 hashCode 使用该可变字段,因此您可以通过对其进行变异来破坏它所在的任何哈希集合。当您更改 compareTo 中使用的字段时,也会出现类似的问题。

Set<Date> dates = new HashSet<Date>();
SortedSet<Date> dates2 = new TreeSet<Date>();
Date d1 = new Date(1), d2 = new Date(2), d3 = new Date(3);
dates.add(d1);
dates.add(d2);
dates.add(d3);
dates2.add(d1);
dates2.add(d2);
dates2.add(d3);
d1.setTime(6);
d2.setTime(5);
d3.setTime(4);
System.out.print("The dates contains [");
for (Date date : dates) {
    System.out.print("date " + date.getTime() + " ");
}
System.out.println("]");
System.out.print("The sorted dates2 contains [");
for (Date date : dates2) {
    System.out.print("date " + date.getTime() + " ");
}
System.out.println("]");
for (int i = 1; i <= 6; i++)
    System.out.println("date " + i + " found is " + dates.contains(new Date(i))
            + " and " + dates2.contains(new Date(i)));

印刷

The dates contains [date 6 date 5 date 4 ]
The sorted dates2 contains [date 6 date 5 date 4 ]
date 1 found is false and false
date 2 found is false and false
date 3 found is false and false
date 4 found is false and false
date 5 found is false and true
date 6 found is false and false

注意:排序后的集合现在的顺序错误。

于 2012-11-28T10:49:31.203 回答
5

如果您重载equals 但不覆盖 equals(Object),就会发生这种情况。

例如,您可能有:

public boolean equals(ActionPlan plan) {
    ...
}

这将被调用:

assertTrue(actionPlan1.equals(actionPlan));

...但不会contains. 你需要:

@Override public boolean equals(Object object) {
    ...
}

当然,这可能不是正在发生的事情。如果没有看到您的代码,我们无法确定。

我不会向您提供有关 ActionPlan 和 Assessment 课程的详细信息,因为这无关紧要。

这个答案与该假设相矛盾......就像彼得的答案一样,其中包含替代故障模式。这就是为什么给出一个简短但完整的例子总是很重要的。

于 2012-11-28T10:48:56.773 回答
0

在我完成了 equals 和 hashCode 并使我的 keyField 最终化后,它仍然不起作用。我又花了一个小时才发现我需要“compareTo”中的这一行:

if (other != null && other.equals(this))
            return 0;
于 2015-01-13T18:32:09.727 回答