经过研究,我仍然找不到我的问题的具体解决方案。我有一个使用 epsilon 的"近似等于"方法,而我的 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
实现是返回一个常量,因为对于任何两个点,都有一个(很长的)中间点链,因此
-
每两个邻居相等,因此
-
每两个邻居必须具有相同的
hashCode
,因此 -
开头和结尾必须具有相同的
hashCode
。
现在,这是一个一致的实现,但显然是一个无用的实现。
我同意 Kayaman 的观点:您的 equals methos 的实现方式,您可以有三个 EPoint(点 A、点 B 和点 C):
pointA.equals(pointB) //true
pointA.equals(pointC) //true
pointB.equals(pointC) //false
这是不允许的。创建具有其他名称的方法可能是一种解决方案。
但是,如果您需要"几乎相等"的对象具有相同的哈希代码,则可以尝试不同的方法:
将每个 EPoint 映射到网格外的 EPoint。例如,如果您的 EPoint 的纬度和纬度浮动,您可以将每个 EPoint 映射到具有四舍五入的 int 值的 EPoint。
如果你需要更高的精度,你可以扩展它并进入第一,第二,...小数位)。
如果你对"映射"点执行 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());
}