这是我在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和评估课程的详细信息,因为它无关紧要。 contains方法失败,而equals和hash则没有。
我不是说java已经破坏或者其他任何东西,我的代码中可能会发生一些有趣的事情。
请注意,我是一名经验丰富的java程序员,我知道dos并不知道实现equals和hashCode。因此,如果我的代码中缺少某些东西,那就不是明显的了。
有没有人见过令人费解的东西?
修改
我在我的代码中做了一些研究,现在我认为问题在于休眠。我在创建之后,在代码的不同部分记录了ActionPlan对象的hashCode,直到调用失败的断言。 不会改变。
我还检查了assessment.getActionPlans()返回的类,它是:
org.hibernate.collection.internal.PersistentSet
我很想相信Set的这个实现不会正确使用equals或hashcode。
有没有人对此有所了解?
答案 0 :(得分:12)
可能有解释
测试最后一种可能性的最简单方法是尝试
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
注意:已排序的集合现在的顺序错误。
答案 1 :(得分:4)
如果重载等于但覆盖 equals(Object)
,则会发生这种情况。
例如,您可能有:
public boolean equals(ActionPlan plan) {
...
}
将由以下人员调用:
assertTrue(actionPlan1.equals(actionPlan));
...但 不会被contains
调用。你需要:
@Override public boolean equals(Object object) {
...
}
当然,这可能不是正在发生的事情。如果没有看到你的代码,我们就无法确定。
我没有向您提供有关ActionPlan和评估类的详细信息,因为它无关紧要。
这个答案与这个假设相矛盾......彼得的回答也是如此,其中包含替代失败模式。这就是为什么给出一个简短但完整的示例总是很重要的。
答案 2 :(得分:0)
在我做了equals和hashCode并使我的keyField成为最终之后,它仍然不起作用。 我花了一个小时才发现我在“compareTo”中需要这一行:
if (other != null && other.equals(this))
return 0;