...
Do not violate any of these five conditions while overriding the equals
method. Mistakes resulting from a violation of to the first condition are infrequent; it is consequently omitted from this discussion. The second and third conditions are highlighted. The rule for consistency implies that mutable objects may not satisfy the equals
contract. It is good practice to avoid defining equals()
implementations that use unreliable data sources such as IP addresses and caches. The final condition about the comparison with null
is typically violated when the equals()
code throws an exception instead of returning false
. Because this does not constitute a security vulnerability, it is beyond the scope of this discussion.
...
This noncompliant code example violates transitivity though it satisfies the symmetry condition. In the first print statement, the comparison between p1
and p2
returns true
, in the second, the comparison between p2
and p3
also returns false
and true
but in the third, the comparison between p1
and p3
returns false
. This is counter intuitive as p1
and p2
must compare equal when they are both equal to a common objectcontradicts the transitivity rule.
Code Block | ||
---|---|---|
| ||
public class Card { private final int number; public Card(int number) { this.number = number; } public boolean equals(Object o) { if (!(o instanceof Card)) return false; Card c = (Card)o; return c.number == number; } } class XCard extends Card { private String type; public XCard(int number, String type) { super(number); this.type = type; } public boolean equals(Object o) { if (!(o instanceof Card)) return false; //normal Card, do not compare type if (!(o instanceof XCard)) return o.equals(this); //It is an XCard, compare type as well XCard xc = (XCard)o; return super.equals(o) && xc.type == type; } public static void main(String[] args) { XCard p1 = new XCard(1, "type1"); Card p2 = new Card(1); XCard p3 = new XCard(1, "type2"); System.out.println(p1.equals(p2)); //returns true System.out.println(p2.equals(p3)); //returns true System.out.println(p1.equals(p3)); //returns false, violating transitivity } } |
...
Wiki Markup |
---|
It is currently not possible to extend an instantiable class (as opposed to an {{abstract}} class) and add a value or field in the subclass while preserving the {{equals}} contract. This implies that composition must be preferred over inheritance. This technique does qualify as a reasonable workaround \[[Bloch 08|AA. Java References#Bloch 08]\]. It can be implemented by giving the {{XCard}} class a private {{card}} field and providing a a {{public}} {{viewCard}} method. |
...