不一致的哈希码和等于 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 一个常数,因为对于任何两个点都有一个(很长的)中间点链,因此
每两个邻居都相等,因此
每两个邻居必须有相同的hashCode
,因此
开头和结尾必须相同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());
}
经过研究我仍然找不到针对我的问题的具体解决方案。我有一个使用 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 一个常数,因为对于任何两个点都有一个(很长的)中间点链,因此
每两个邻居都相等,因此
每两个邻居必须有相同的
hashCode
,因此开头和结尾必须相同
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());
}