Несовместимый хэш-код и равно 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 реализация заключается в возвращении константы, потому что для любых двух точек существует (очень длинная) цепочка промежуточных точек, так что

  1. каждые два соседа равны, поэтому

  2. каждые два соседа должны иметь одинаковые hashCode, следовательно

  3. начало и конец должны иметь одинаковые 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());
}
Другие вопросы по тегам