After researching I still can't find the specific solution for my problem. I have an "approximately equals" method that uses an epsilon, while my hashCode method uses the exact values. This breaks the precondition of HashSet when I compare the values.
@Override
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof EPoint)) {
return false;
}
EPoint ePoint = (EPoint) o;
return Math.abs(Math.abs(ePoint.lat) - Math.abs(lat)) < EPSILON && Math.abs(Math.abs(ePoint.lon) - Math.abs(lon)) < EPSILON;
}
@Override
public int hashCode() {
return Objects.hash(lat, lon);
}
I can't find a way to make the hasCode() consistent with my equals method.
You must override hashCode() in every class that overrides equals(). Failure to do so will result in a violation of the general contract for Object. hashCode(), which will prevent your class from functioning properly in conjunction with all hash-based collections, including HashMap, HashSet, and Hashtable.
Overriding only equals() method without overriding hashCode() causes the two equal instances to have unequal hash codes, which violates the hashCode contract (mentioned in Javadoc) that clearly says, if two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two ...
If you don't override hashcode() then the default implementation in Object class will be used by collections. This implementation gives different values for different objects, even if they are equal according to the equals() method.
Your equals
itself breaks the contract even before you get to hashCode
because it isn't transitive.
This also immediately leads to the only consistent hashCode
implementation being to return a constant, because for any two points there is a (very long) chain of intermediate points so that
every two neighbors are equal, therefore
every two neighbors must have the same hashCode
, therefore
beginning and end must have the same hashCode
.
Now, this is a consistent implementation, but quite obviously a useless one.
I agree with Kayaman: The way your equals methos is implemented, you can have three EPoints (pointA,pointB,and pointC) with:
pointA.equals(pointB) //true
pointA.equals(pointC) //true
pointB.equals(pointC) //false
And this is not allowed. Creating a method with another name might be a solution.
If, however, you need your "almost Equal" objects to have the same hashcode, you could try a different approach:
Map every EPoint to an EPoint out of a grid. If, e.g. your EPoint's lat and lon where floats, you could map each EPoint to an EPoint with the rounded int-values.
If you need higher precision, you could extend on that and go into first, second,...decimal place).
If you do the equals() and the hashcode() method against the "mapped" Point, this should satisfy all requirements:
@Override
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof EPoint)) {
return false;
}
EPoint ePoint = (EPoint) o;
return this.gridLon() == ePoint.gridLon() && ePoint.gridLat() == this.gridLat();
}
@Override
public int hashCode() {
return Objects.hash(this.gridLon(), this.gridLat());
}
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