哈希集的奇怪行为

时间:2019-06-03 14:35:29

标签: java equals hashset hashcode

我在弄乱试图了解HashSets的行为时遇到了麻烦,但遇到了一个我无法理解的问题。第2和第3狗对象具有相同的名称,并且equals()hashcode()已被覆盖以使名称表示相等。尽管如此,hashSet仍然有重复项,我不知道为什么。

我重新阅读了Head First Java的“数据结构”一章,但它仍然表明我的代码应该在理论上可以正常工作。

public class DataStructsTests<E> {

HashSet<Dogs> tree = new HashSet<Dogs>();
HashSet<Dogs> treeOwner = new HashSet<Dogs>();

public static void main(String[] args) {
    DataStructsTests<String> d = new DataStructsTests<String>();
    d.go();
}

public void go() {
    Dogs dog = new Dogs("Scout", "a");
    tree.add(dog);
    treeOwner.add(dog);

    Dogs dog2 = new Dogs("Brodie", "b");
    tree.add(dog2);
    treeOwner.add(dog2);

    Dogs dog3 = new Dogs("Brodie", "c");
    tree.add(dog3);
    treeOwner.add(dog3);

    System.out.println(tree);
    System.out.println(treeOwner);

    System.out.println(dog2.equals(dog3));
    System.out.println(dog2.hashCode() + " " + dog3.hashCode());
}

class Dogs {
    private String name;
    private String ownerName;

    public Dogs(String n, String o) {
        name = n;
        ownerName = o;
    }

    public boolean equals(Dogs d) {
        return name.equals(d.getName());
    }

    public int hashCode() {
        return name.hashCode();
    }

         public String getName() {
        return name;
    }

             public String toString() {
        return name;
    }

运行程序将返回以下内容:

[Brodie, Brodie, Scout]
[Brodie, Brodie, Scout]
true
1998211617 1998211617

即使equals()返回true并且哈希码相同,重复项仍然保留。

编辑:原来的问题是,当我使用Dog而不是Object时,我没有正确覆盖equals()方法。

1 个答案:

答案 0 :(得分:5)

equals接受类型为Object的对象,该对象被HashSet调用。您需要类似的东西:

@Override
public boolean equals(Object d) {
    if (! d instanceof Dogs){
         return false;
    }
    return name.equals(((Dogs) d).getName());
}

以下是此答案的组成部分:

  1. public boolean equals(Object d)-equals(至少是从Object继承的版本)定义为使用Object,因此要覆盖它,还必须使用{{ 1}}。
  2. Object-告诉编译器是否警告您,如果您像在问题中一样犯了错误。
  3. @Override-首先检查输入的d instanceof Dogs甚至是Object
  4. Dogs-强制转换为((Dogs) d).getName()的原因是因为Dogs现在以d的形式传递,所以您不会自动获得对{除非您明确表示要将Object视为Dogs,否则{1}}的方法。

最后一点要注意:Java中的常规约定是用单数形式命名类,除非出于某些原因相信每个实例将包含多个对象。这是为了避免歧义。 Object清楚说明Dogs是什么;显然是Dog dd到底是什么? Dog是否有很多狗,而它们没有自己的对象类型?变得有点模棱两可。