【问题标题】:HashSet contains method, strange behavior [duplicate]HashSet包含方法,奇怪的行为[重复]
【发布时间】:2011-07-27 05:01:06
【问题描述】:

这是我的代码:

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,到这个集合如果这个集合 不包含元素 e 使得 (o==null ? e==null : o.equals(e))

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

非常感谢您的回答!

【问题讨论】:

    标签: java


    【解决方案1】:

    当您覆盖equals 时,您还必须覆盖hashCode。否则,相等的对象将具有不同的哈希码并被视为不相等。

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

    【讨论】:

    • 它们不会被认为是不平等的。只是 HashSet 甚至不会调用 equals 方法,因为它只对通向同一个存储桶的 hashCodes 执行此操作。并且仅覆盖 hashCode 没有任何意义,因为 HashSet 将始终为具有相同 hashCodes 的对象调用 equals。
    • @JB,是的,它们指向不同的存储桶这一事实意味着它们被认为是“不平等的”(被认为是不同的对象)。当我使用该术语时,我指的不是equals 方法。我也同意仅覆盖 hashCode 是不合逻辑的,这就是我强烈建议不要这样做的原因。但是,它不会违反合同。
    • 如果java文档提到hashcode首先被调用就好了。我刚刚在 java 5 中被这个问题所困扰。
    • @Aaron,这不仅会很好,而且我认为目前它的文档完全不正确,并且这种情况一直持续到当今的 Java。它说 contains 和 add 方法等价于 Objects.equals,但它们显然不是。
    【解决方案2】:

    还应该实现hashCode,使其与equals一致。 HashSet 使用hashCode 方法来决定将一个项目放入哪个桶中,并且只有当两个项目的哈希码相同时才调用equals

    Effective Java, 2nd Edition第 9 条中讨论了这条规则(以及违反它的后果):当你覆盖 equals 时,总是覆盖 hashCode

    【讨论】:

    • 非常感谢大家,这真的很有帮助,我在你回答之前找到了答案(不知道如何取消问题),但你写的是我所做的,它解决了我的问题;)。
    【解决方案3】:

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

    实现一个 hashcode 方法,如果 a.equals(b) == true,那么 a.hashCode() == b.hashCode()

    它应该会按您的预期开始工作。

    【讨论】:

      【解决方案4】:

      由于大多数 cmets 已经...只需覆盖 hashcode 方法(示例如下),你应该很好。

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

      【讨论】:

      猜你喜欢
      • 2019-04-15
      • 2012-03-16
      • 1970-01-01
      • 2015-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多