23
votes

Until now, my understanding was that == is an operator overload for .equals(). However, I recently discovered that

new Integer(1) == new Long(1) // returns true

whereas

new Integer(1).equals(new Long(1)) // returns false

so I guess == is not exactly a shorthand for .equals(), so how does it determine equality?

2
This continues to bite me when using GORM, which has Long database IDs. Requests from JSON generated integer values yielding behavior like: groovy:000> m = [1L : 'foo'] ===> [1:foo] groovy:000> m.containsKey(1L) ===> true groovy:000> m.containsKey(1) ===> false - Ron Dahlgren

2 Answers

23
votes

== in Groovy is roughly equivalent to equals(), however, you'll find it's different from Java when comparing different classes with the same value - if the class is Comparable. Groovy also does type casting if possible.

If you check out the code, it looks like ultimately compareToWithEqualityCheck() is executed for ==.

10
votes

It turns out == does not delegate to equals(), it delegates to compareTo. So == will return true if a.compareTo(b) returns 0

So in this particular case

new Integer(1).compareTo(new Long(1)) == 0

so therefore:

new Integer(1) == new Long(1)

but this does not necessarily mean that

new Integer(1).equals(new Long(1))

The reason why this is all so weird and confusing is because the contract of Comparable does not require that it is consistent with equals, though it is strongly recommended.

It is strongly recommended (though not required) that natural orderings be consistent with equals. This is so because sorted sets (and sorted maps) without explicit comparators behave "strangely" when they are used with elements (or keys) whose natural ordering is inconsistent with equals.