HashSet包含方法,奇怪的行为

7

这是我的代码:

public class testGui {



    public static void main(String[] arg){
        class TESTS{
            String t;

            public TESTS(String t){
                this.t = t;
            }

            @Override
            public boolean equals(Object x){
                System.out.println("My method is called...");
                if(x instanceof TESTS){
                    TESTS zzz = (TESTS) x;
                    return zzz.t.compareTo(t)==0;
                }
                else return false;
            }
        }
        HashSet<TESTS> allItems = new HashSet<TESTS>();
        allItems.add(new TESTS("a"));
        allItems.add(new TESTS("a"));
        System.out.println(allItems.contains(new TESTS("a")));
    }

}

我不明白为什么HashSet的contains方法没有按照它们的规范调用我的equals方法:

更正式地说,如果此集合不包含满足(o==null ? e==null : o.equals(e))的元素e,则将指定元素o添加到该集合中。

我的代码返回false并且没有进入我的equals方法。

非常感谢您的回答!

4个回答

13

当您重写 equals 时,您必须同时重写 hashCode。否则,相同的对象将具有不同的哈希码并被认为是不相等的。

强烈建议不要仅重写 hashCode。但这不是必需的,因为不相等的对象可以具有相同的哈希码。


2
它们不会被视为不相等。只是 HashSet 不会调用 equals 方法,因为它仅对导致相同桶的哈希码执行此操作。而仅覆盖 hashCode 没有任何意义,因为 HashSet 总是为具有相同 hashCode 的对象调用 equals。 - JB Nizet
@JB,是的,它们导致不同的桶,意味着它们被认为是“不相等”的(被认为是不同的对象)。当我使用该术语时,我并未指涉equals方法。我也同意仅覆盖hashCode是不合逻辑的,这就是为什么我强烈建议不要这样做。但是,它并不会违反契约。 - Matthew Flaschen
1
如果Java文档提到了先调用HashCode,那就太好了。我在Java5中刚刚因此问题而受到影响。 - Aaron
@Aaron,不仅仅是好的建议,我认为目前这个文档的描述是错误的,并且这个错误一直延续到了现在的Java。它说contains和add方法等同于Objects.equals,但事实证明它们并不相同。 - Tim M.

7

HashSet依赖于每个对象的HashCode。在调用equals方法之前,将调用hashCode方法。如果hashcode相等,则HashSet认为值得评估equals方法。

实现hashCode方法,使得a.equals(b) == true时,a.hashCode() == b.hashCode()

这样它就会按照你预期的方式开始工作。


3
你还应该实现hashCode,以便与equals一致。 HashSet使用hashCode方法来决定将项目放入哪个桶中,并仅在两个项目的哈希码相同时调用equals
《Effective Java第二版》在条款9:覆盖equals时总是要覆盖hashCode中讨论了这一规则(以及违反它的后果)。

非常感谢大家,你们的帮助真的很有用。在你们回答之前,我已经找到了答案(不知道如何取消问题),但是你们所写的内容正是我所做的,解决了我的问题 ;)。 - Abbadon

0

由于大多数评论都是...只需覆盖哈希码方法(示例如下),您就可以了。

@Override
        public int hashCode() {
            return t.hashCode()*31;
        }

用31相乘会得到什么收益? - JB Nizet
这个线程会帮助解答:https://dev59.com/gnVC5IYBdhLWcg3wbQfA - Prasanna

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接