Spare me a few more minutes and I will convince you that you must give the article a serious once over. I for one got a better appreciation of the complexity of the problem -- if you want it addressed fully.
The article warms up around the 3rd of the four pitfalls they identify
- Defining equals with the wrong signature
- Changing
equals
without also changing hashCode - Defining
equals
in terms of mutable fields - Failing to define
equals
as an equivalence relation
equals
method implementation will result in it disappearing from the collection.
public class Point {
private int x, y;
public Point(int i, int j) { x = i; y = j; }
public int getX() { return x; }
public void setX(int i) { x = i; }
public int getY() { return y; }
public void setY(int i) { y = i; }
@Override public int hashCode() { return 41 * (41 + getX()) + getY(); }
@Override public boolean equals(Object other) {
boolean result = false;
if (other instanceof Point) {
Point that = (Point) other;
result = (this.getX() == that.getX() && this.getY() == that.getY());
}
return result;
}
}
..
HashSet hashSet = new HashSet();
Point p = new Point(1, 2);
hashSet.add(p);
p.setX(12);
System.out.println(hashSet.contains(p)); // <-- Prints false!!
Yep! A forehead smacking moment alright. The article suggests a way around this problem. Which leads us to the 4th pitfall -- that of equivalence. This means that for non-null values, the following is true about the equals method:
- Reflexivity: x.equals(x)
- Symmetry: x.equals(y) => y.equals(x)
- Transitivity:x.equals(y) and y.equals(z) => x.equals(z)
- Consistence: x.equals(y) always returns the same result
- x.equals(null) is always false