不一致的哈希码和等于 java

Inconsistent hashcode and equals java

经过研究我仍然找不到针对我的问题的具体解决方案。我有一个使用 epsilon 的 "approximately equals" 方法,而我的 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 方法一致的方法。

您的 equals 本身甚至在您到达 hashCode 之前就违反了合同,因为它不是可传递的。

这也立即导致唯一一致的 hashCode 实现是 return 一个常数,因为对于任何两个点都有一个(很长的)中间点链,因此

  1. 每两个邻居都相等,因此

  2. 每两个邻居必须有相同的hashCode,因此

  3. 开头和结尾必须相同hashCode

现在,这是一个 一致的 实现,但很明显是一个无用的实现。

我同意 Kayaman 的观点:您的 equals 方法的实现方式,您可以拥有三个 EPoints(pointA、pointB 和 pointC):

pointA.equals(pointB) //true
pointA.equals(pointC) //true
pointB.equals(pointC) //false

这是不允许的。使用其他名称创建方法可能是一种解决方案。

但是,如果您需要 "almost Equal" 对象具有相同的哈希码,您可以尝试不同的方法:
将每个 EPoint 映射到网格外的 EPoint。如果,例如你的 EPoint 的纬度和经度在哪里浮动,你可以将每个 EPoint 映射到具有四舍五入的 int 值的 EPoint。
如果你需要更高的精度,你可以扩展它并进入第一,第二,...小数位)。

如果你对 "mapped" 点执行 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());
}