【问题标题】:What is the cause of this odd behaviour from Hashset in Java? [duplicate]Java中Hashset的这种奇怪行为的原因是什么? [复制]
【发布时间】:2019-10-19 03:18:02
【问题描述】:

我一直在试图了解 HashSet 的行为方式,但我遇到了这个我无法理解的问题。第 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 并且哈希码相同,但仍然存在重复项。

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

【问题讨论】:

  • 您尚未覆盖equals 方法。它必须有一个Object 类型的参数才能被覆盖。这只是一个过载。
  • 这就是为什么您应该始终在实际尝试覆盖时将@Override 添加到方法中。

标签: java equals hashset hashcode


【解决方案1】:

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的版本,被定义为采用Objects,因此要覆盖它,您还必须采用Object
  2. @Override - 告诉编译器如果你犯了你在问题中犯的错误,就会警告你。
  3. d instanceof Dogs - 首先检查输入的 Object 是否甚至是 Dogs
  4. ((Dogs) d).getName() - 强制转换为 Dogs 的原因是因为 d 现在作为 Object 传入,因此您不会自动访问 Dogs 的方法,除非您明确表示您想以Dogs 的形式查看Object

最后一点:Java 中的一般约定是以单数命名类,除非有理由相信每个实例都是多个事物。这是为了避免歧义。 Dog d 明确了 d 是什么;显然是DogDogs d 到底是什么? d 是不是很多狗,只是没有自己的对象类型?它变得有点模棱两可。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-05
    • 1970-01-01
    • 1970-01-01
    • 2017-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-30
    相关资源
    最近更新 更多