作者:Tony_Friday | 来源:互联网 | 2022-12-18 14:44
我最近正在做一个涉及一套的基本任务,我偶然发现了一个奇怪的问题.我有以下课程:
public static class Quadruple {
int a;
int b;
int c;
int d;
Map histogram;
public Quadruple(int a, int b, int c, int d) {
this.a = a;
this.b = b;
this.c = c;
this.d = d;
this.histogram = new HashMap<>();
histogram.put(a, histogram.get(a) == null ? 1 : histogram.get(a) + 1);
histogram.put(b, histogram.get(b) == null ? 1 : histogram.get(b) + 1);
histogram.put(c, histogram.get(c) == null ? 1 : histogram.get(c) + 1);
histogram.put(d, histogram.get(d) == null ? 1 : histogram.get(d) + 1);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Quadruple)) {
return false;
}
Quadruple q = (Quadruple) obj;
return q.histogram.equals(this.histogram);
}
@Override
public int hashCode() {
return Objects.hash(a, b, c, d);
}
当我初始化这种类型的2个对象时:
Quadruple q1 = new Quadruple(1, 1, 1, 2);
Quadruple q2 = new Quadruple(1, 1, 2, 1);
q1.equals(q2)返回true,但两个对象可以单独添加到HashSet.现在我从HashSet的契约中理解,如果你试图添加的对象是equals()一个已经存在的对象,那么它应该被认为存在并且不应该做任何事情.我设法通过使用LinkedList并在添加它之前检查列表是否包含()对象来避免这个问题,这似乎相应地起作用.
我的问题是,这种行为是否正常,因为我检查了底层实现,并发现HashSet中使用的HashMap实际上使用equals()检查值.有什么我可能会失踪?
1> Jaroslaw Paw..:
您的equals
方法会进行比较histogram
,但您会hashCode
计算来自其他4个字段的哈希值.你的hashCode
方法实现违反了equals
和之间的契约hashCode
,它说如果两个对象相等,它们必须具有相同的哈希值.
如果你看一下你的实现,Objects.hash
你会得到这段代码:
public static int hashCode(Object a[]) {
if (a == null)
return 0;
int result = 1;
for (Object element : a)
result = 31 * result + (element == null ? 0 : element.hashCode());
return result;
}
正如你在循环中看到的那样,参数的顺序传递给了Object.hash
问题.
至于解决方案,我真的没有理由拥有除了以外的领域histogram
.无论哪种方式,给定equals
方法的实现,您的hashCode
方法应如下所示:
@Override
public int hashCode() {
return histogram.hashCode();
}