Несовместимый хэш-код и равно Java
После исследования я все еще не могу найти конкретное решение для моей проблемы. У меня есть метод "приблизительно равно", который использует эпсилон, в то время как мой метод hashCode использует точные значения. Это нарушает предварительное условие HashSet, когда я сравниваю значения.
@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);
}
Я не могу найти способ сделать hasCode() совместимым с моим методом equals.
2 ответа
Ваш equals
сам нарушает договор еще до того, как hashCode
потому что это не транзитивно.
Это также сразу приводит к единственному hashCode
реализация заключается в возвращении константы, потому что для любых двух точек существует (очень длинная) цепочка промежуточных точек, так что
каждые два соседа равны, поэтому
каждые два соседа должны иметь одинаковые
hashCode
, следовательноначало и конец должны иметь одинаковые
hashCode
,
Это последовательная реализация, но совершенно бесполезная.
Я согласен с Каяманом: в способе реализации ваших методов равенства вы можете получить три EPoints (pointA,pointB и pointC) с:
pointA.equals(pointB) //true
pointA.equals(pointC) //true
pointB.equals(pointC) //false
И это не разрешено. Создание метода с другим именем может быть решением.
Однако если вам нужно, чтобы у ваших "почти равных" объектов был одинаковый хэш-код, вы можете попробовать другой подход:
Сопоставьте каждый EPoint с EPoint из сетки. Если, например, широта и долгота вашего EPoint, где плавает, вы можете сопоставить каждый EPoint с EPoint с округленными int-значениями.
Если вам нужна более высокая точность, вы можете расширить это и перейти на первое, второе,... десятичное место).
Если вы используете метод equals() и hashcode() для сопоставленной точки, это должно удовлетворить все требования:
@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());
}