Our code is very similar to Inserting strings into a
Set
. :
final Set<Coordinate> points = new HashSet<Coordinate>();
points.add(new Coordinate(1, 2));
points.add(new Coordinate(4, 1));
points.add(new Coordinate(1, 2));
System.out.println("The set contains " + points.size() + " elements:");
for (final Coordinate c : points) {
System.out.println(c.toString());
}
Since we do have set semantics we expect the duplicate
coordinate value (1|2)
to be dropped and thus to
appear only once. So our set should contain {(4|1),
(1|2)}
. We however see the duplicate object appearing on
standard output:
The set contains 3 elements:
(4|1)
(1|2)
(1|2)
This is due to our own fault not providing a hashCode()
implementation being compatible to our overridden equals()
method. Consider:
final Coordinate
c12 = new Coordinate(1, 2),
c12Duplicate = new Coordinate(1, 2);
System.out.println("c12.hashCode() and c12Duplicate.hashCode():"+
c12.hashCode() + "," + c12Duplicate.hashCode());
This yields the following output:
c12.hashCode() and c12Duplicate.hashCode():1334574952,1882008996
Apparently the two instances c12 and c12Duplicate are
equal to each other. Their hash codes however are different
clearly violating the contract being described in Java
Collections - hashCode() and equals(). The values
actually stem from hashCode()
being defined in our superclass Object
.
The former exercise Inserting strings into a
Set
.
involved instances of class String having well defined
equals()
and hashCode()
implementations. To resolve this issue we thus have to override
not just equals()
but hashCode()
as well:
public class Coordinate {
private int x, y;
...
@Override
public int hashCode() {
return Long.valueOf(x * 31 + y).hashCode();
}
}
This yields:
c12.hashCode() and c12Duplicate.hashCode():33,33
And finally:
The set contains 2 elements:
(1|2)
(4|1)