Java Crazyness - 当equals通过时包含失败

pho*_*360 4 java contains equals set

这是我在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));
Run Code Online (Sandbox Code Playgroud)

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

我没有向您提供有关ActionPlan和评估课程的详细信息,因为它无关紧要.contains方法失败,而equals和hash则没有.

我不是说java已经破坏或者其他什么,我的代码中可能会发生一些有趣的事情.

请注意,我是一名经验丰富的java程序员,我知道dos并不知道实现equals和hashCode.因此,如果我的代码中缺少某些东西,那就不是显而易见的了.

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

编辑

我在我的代码中做了一些研究,现在我认为问题在于休眠.我在创建之后,在代码的不同部分记录了ActionPlan对象的hashCode,直到调用失败的断言.它没有改变.

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

org.hibernate.collection.internal.PersistentSet
Run Code Online (Sandbox Code Playgroud)

我很想相信Set的这个实现不能正确使用equals或hashcode.

有没有人对此有所了解?

Pet*_*rey 12

有可能解释

  • 你有一个不使用equals或hashCode的有序集.
  • 你有"覆盖"等于(MyClass)而不是equals(Object)
  • hashCode使用的字段已更改.这使Set处于不可用的状态.

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

assertTrue(new HashSet(actionPlans).contains(actionPlan1));
Run Code Online (Sandbox Code Playgroud)

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


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)));
Run Code Online (Sandbox Code Playgroud)

版画

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
Run Code Online (Sandbox Code Playgroud)

注意:已排序的集合现在顺序错误.


Jon*_*eet 5

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

例如,您可能有:

public boolean equals(ActionPlan plan) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

这将被调用:

assertTrue(actionPlan1.equals(actionPlan));
Run Code Online (Sandbox Code Playgroud)

...但不会调用contains。你需要:

@Override public boolean equals(Object object) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

当然,也有可能事实并非如此。如果没有看到您的代码,我们无法确定。

我不会向您提供有关行动计划和评估课程的详细信息,因为这并不重要。

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

  • @phoenix7360:仅仅因为您*声称*了解良好实践并不意味着您实际上*确实*了解它们。这就是为什么您应该提供代码(这是另一个好的实践)。 (2认同)