Crazy Java - Contains a crash when passing peers

This is the craziest thing I've seen in 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)); 

The first two statements are passed on, but the last failed.

I do not give you details about the ActionPlan and Assessment classes, because it does not matter. The contains method does not work, where there are no equal and hash.

I am not saying that java is broken or something else, there is something funny in my code.

Please note that I am an experienced Java programmer, and I know about dos and not for implementing equals and hashCode. Therefore, if something is missing in my code, it is not something obvious.

Has anyone seen something mysterious?

EDIT

I did some research in my code, and now I think the problem is in sleep mode. I registered the hashCode of the ActionPlan object, after creation, and in different parts of the code until the calling failing call was called. He does not change .

I also checked the class returned by the .getActionPlans () evaluation method, and this:

 org.hibernate.collection.internal.PersistentSet 

I am tempted to believe that this implementation of Set does not use peers or hashcode correctly.

Does anyone know about this?

+4
source share
3 answers

Possible explanations

  • You have a sorted set that does not use equals or hashCode.
  • You have "overriden" equals (MyClass) instead of equals (Object)
  • The fields used by the hash code are changing. This leaves Set in a state that cannot be used.

The easiest way to check the last opportunity is to try

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

I suspect this will pass in your case .;)


The date has the disadvantage that it is changed, and hashCode uses the changed fields so that you can damage any hash collection that it is in by changing it. A similar problem occurs when you change the field that is used in 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))); 

prints

 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 

Note: The sorted collection is now in the wrong order.

+9
source

This will happen if you overload equals, but do not override equals(Object) .

For example, you might have:

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

This will be called:

 assertTrue(actionPlan1.equals(actionPlan)); 

... but will not be called contains . You need:

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

Of course, it is possible that this is not what is happening. We cannot say for sure without seeing your code.

I do not give you details about the ActionPlan and Assessment classes, because it does not matter.

This answer contradicts this assumption ... as Peter answers, which contains alternative failure modes. This is why providing a short but complete example is always important.

+4
source

After I made equals and hashCode, and made my key finale, it still doesn't work. It took me another hour to find out that I needed this line in "compareTo":

 if (other != null && other.equals(this)) return 0; 
0
source

All Articles