如何在值处于±10范围内时正确实现equals()与hashCode()方法
问题分析与解决方案
首先要明确:Java中equals()方法必须遵守等价关系契约(自反、对称、传递、一致),你当前的equals()实现违反了传递性,这会导致HashMap、HashSet等哈希集合出现异常行为。比如:
- 实例a的value=5,实例b的value=15,实例c的value=25
a.equals(b)返回true,b.equals(c)返回true,但a.equals(c)返回false
这种情况不符合等价关系,会让集合无法正确判断元素是否重复。
方案1:修正equals()使其符合契约,再实现hashCode()
如果要让equals()合法,应该将value划分成大小为10的区间,只有落在同一区间的两个值才判定相等(保证传递性)。
修正后的完整代码
public class Test { private double value; // 补充构造方法以便实例化对象 public Test(double value) { this.value = value; } private boolean isEqualValues(final double valueOne, final double valueTwo) { // 将值划分到[10n, 10(n+1))的区间,同一区间则判定相等 long bucketOne = (long) Math.floor(valueOne / 10.0); long bucketTwo = (long) Math.floor(valueTwo / 10.0); return bucketOne == bucketTwo; } @Override public boolean equals(final Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Test test = (Test) o; return isEqualValues(test.value, value); } @Override public int hashCode() { // 基于区间索引生成hashCode,同一区间的对象hashCode必然相同 long bucket = (long) Math.floor(value / 10.0); return Long.hashCode(bucket); } }
方案2:坚持原有equals()逻辑(不推荐)
如果你一定要保留当前“差值±10即相等”的判断(即使违反契约),那唯一能满足equals()相等则hashCode()相同的方式是让所有对象返回同一个固定hashCode:
@Override public int hashCode() { return 42; // 任意固定整数均可 }
但这种做法会让哈希集合的性能暴跌——所有元素都会被放入同一个哈希桶,查询、插入操作的时间复杂度从O(1)退化为O(n),仅适合极端场景。
另外,原代码中的isEqualValues()方法缺少闭合的},已在方案1的代码中修正。
内容的提问来源于stack exchange,提问作者casao01
相关产品推荐
相关产品推荐

