The contract for equals(object)
method specifies 4 properties to follow: Reflexive, Symmetric, Transitive and Consistent. While I understand the danger of not following Reflexive, Symmetric and Consistent , and can definitely agree its good to follow transitive, I was wondering what harm it would bring if its violating the Transitive property?
Specifically, which of the Java library (or various third party libraries) need the dependency upon equals
to be transitive to work correctly? In my understanding, the Collections framework will work if the other 3 properties are well implemented.
equals(x) returns true. It is transitive: for any reference values x, y, and z, if x. equals(y) returns true and y. equals(z) returns true, then x.
Java String equals() Method The equals() method compares two strings, and returns true if the strings are equal, and false if not. Tip: Use the compareTo() method to compare two strings lexicographically.
The equals() method must be: reflexive: An object x must be equal to itself, which means, for object x, equals(x) should return true. symmetric: for two given objects x and y, x. equals(y) must return true if and only if equals(x) returns true.
So while the equals() function first checks if two objects are the same and then compares the value of the objects' attributes, the hashCode method compares them by using only their hash codes and gives us a conclusion. It is used for more efficient storage of data by collections. This facilitates quicker access.
Assume three objects a,b,c with
a == a, b == b, c == c (reflexive) a == b, b == a b == c, c == b a != c, c != a
(Pseudocode, x == y
stands for x.equals(y)
).
Now, let's add the objects to a set:
Set s = new HashSet(); // Set implementation doesn't matter s.add(b); // s = [b] s.add(a); // s doesn't change, because a == b s.add(c); // s doesn't change, because c == b
In contrast, if we were to add them in a different order:
Set s = new HashSet(); s.add(a); // s = [a] s.add(b); // s doesn't change, because b == a s.add(c); // s = [a,c], because c != a
That is clearly counter-intuitive and doesn't match the behavior one would expect of a set. For example, it would mean that the union of two sets (i.e. the state of s after s.addAll(someOtherSet)
) could depend on the implementation (order of elements) of someOtherSet.
At the moment I am not aware of a Java API that has problems with the absence of transitivity. (I am still reflecting for an example).
But independent of that, transitivity is required for equality because that is the mathematical algebraical definition of the equality relation. http://en.wikipedia.org/wiki/Equality_(mathematics)
If transitivity is not present the method must not be called equals because this would be misleading taking into account the expectation one has when hearing/reading "equality". This would contradict the principle of least astonishment. http://en.wikipedia.org/wiki/Principle_of_least_astonishment
[EDIT]
The interesting thing about this is that strictly mathematical speaking the "equality" defined by the java equals method is not an equality but rather the more general equivalence relation http://en.wikipedia.org/wiki/Equivalence_relation because different objects can also be "equal" according to java, thus contradicting the antisymmetry property required for a true equality.
Conclusion:
.equals in Java is a equivalence relation (which still requires transitivity)
== in Java is an equality (or identity) relation
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With