我最近正在做一个涉及一套的基本任务,我偶然发现了一个奇怪的问题。我有以下课程:
function myFunction() {
//getting the html
var copyText = document.getElementById("myInput").outerHTML;
copyText.select();
document.execCommand("Copy");
//remove value
alert("Copied the text: " + copyText);
}
当我初始化这种类型的2个对象时:
public static class Quadruple {
int a;
int b;
int c;
int d;
Map<Integer, Integer> 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);
}
q1.equals(q2)返回true,但两个对象可以分别添加到HashSet。 现在我从HashSet的契约中理解,如果你试图添加的对象是equals()一个已经存在的对象,那么它应该被认为存在并且不应该做任何事情。 我已经设法通过使用LinkedList并在添加它之前检查列表是否包含()对象来解决此问题,这似乎相应地起作用。
我的问题是,这种行为是否正常,因为我检查了底层实现,并发现HashSet中使用的HashMap实际上使用equals()检查值。有什么我可能会失踪吗?
答案 0 :(得分:5)
您的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();
}