哈希集的奇怪行为

L29*_*092 2 java equals hashcode hashset

我在弄乱试图理解HashSet的行为时遇到了麻烦,但遇到了一个我无法理解的问题。第二个和第三个狗对象具有相同的名称,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;
    }
Run Code Online (Sandbox Code Playgroud)

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

[Brodie, Brodie, Scout]
[Brodie, Brodie, Scout]
true
1998211617 1998211617
Run Code Online (Sandbox Code Playgroud)

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

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

Ben*_* I. 5

equals采用类型的目的Object,这是通过被称为一个HashSet。您需要类似:

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

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

  1. public boolean equals(Object d)- equals,至少是从继承的版本Object定义为Object,因此要覆盖它,还必须使用Object
  2. @Override -告诉编译器警告您,如果您像在问题中一样犯了错误。
  3. d instanceof Dogs-检查Object馈入是否甚至是Dogs第一个。
  4. ((Dogs) d).getName()-之所以投来Dogs是因为d目前正在通过为Object,这样你就不会自动获取Dogs的方法,除非你明确地说,您要查看的Object作为Dogs

最后一点:Java中的常规约定是使用单数形式命名类,除非出于某些原因相信每个实例将包含多个对象。这是为了避免歧义。 Dog d明确什么d是; 显然是一个Dog。究竟是Dogs d什么?有d很多只狗,但是它们没有自己的对象类型?它变得有点模棱两可。