HashSet插入2个相等的元素

时间:2018-05-04 14:12:15

标签: java equals hashset hashcode

我最近正在做一个涉及一套的基本任务,我偶然发现了一个奇怪的问题。我有以下课程:

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()检查值。有什么我可能会失踪吗?

1 个答案:

答案 0 :(得分:5)

您的equals方法会比较histogram,但您的hashCode会计算来自其他4个字段的哈希值。您对hashCode方法的实施违反了equalshashCode之间的合同,该合同规定如果两个对象相同,则必须使用相同的哈希值。

如果您查看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();
}