【问题标题】:Need clarification about HashSet and duplicates in Java需要澄清 Java 中的 HashSet 和重复项
【发布时间】:2013-12-22 16:55:56
【问题描述】:

我需要澄清一下 java 认为什么是重复的。

考虑以下代码:

public class Fruit {

    private String name;
    private int juice;

    public Fruit(String name, int j) {
        this.name=name;
        this.juice=j;
    }

    //some more code here

    public String toString() {
        return this.name;
    }

    public boolean equals(Object fruit) {
        return (((Fruit)fruit).name.equals(this.name));
    }
}

public class Test {

    public static void main(String[] args) {

        Fruit a=new Fruit("Apple", 25);
        Fruit b=new Fruit("Apple", 22);

        HashSet<Fruit> hs=new HashSet<Fruit>();

        hs.add(a);
        hs.add(b);

        System.out.println(a.equals(b));
        System.out.println(hs.size());

    }
}

我创建了一个 Fruit 类,我在其中重写了 equals(),因此如果两个对象的名称相同,则它们被视为相等。 然后,我将两个 Fruit 对象(同名)添加到 HashSet。

现在,HashSet 应该防止尝试添加两个相等的对象。 虽然,上述代码的输出是:

真 2

所以一方面,Java 将这两个对象(a 和 b)视为相等,另一方面 - HashSet 不认为这两个对象相等。 那么我在这里错过了什么?

提前致谢!

【问题讨论】:

  • 我会注意HashSet 的含义。为什么它有“哈希”部分:)
  • 谢谢大家的回答。我将覆盖 HashCode()。还有一个问题:如果我将使用其他不允许重复且不使用哈希的数据结构,例如 TreeSet,该怎么办?
  • 如果你使用TreeSet,你要么必须传递知道如何比较水果的Comparator对象,要么让Fruit实现Comparable,所以它也需要额外的工作。
  • 我不知道标准 JDK 中的任何 Set 实现仅使用 equals 方法。

标签: java duplicates hashset


【解决方案1】:

HashSet 不认为这两个是相等的。所以我错过了什么 在这里?

您错过了在 Fruit 类中覆盖 hashCode

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

【讨论】:

    【解决方案2】:

    这是您的 hashCode() 方法中的问题。您必须同时覆盖 equals()hashCode() 方法。

    【讨论】:

      【解决方案3】:

      首先,您对equals 的实现是错误的。您将参数转换为Fruit,而没有先检查它是否确实是Fruit 的实例。

      其次,在覆盖equals 时,您必须 也覆盖hashCode。见http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode()

      【讨论】:

        【解决方案4】:

        HashSet 和 HashMap 使用两个东西来检查相等性。

        首先,它使用 getHashCode() 检查两个对象的 HashCode。

        当且仅当 HashCode 匹配时,才使用 equals() 方法检查相等性。

        如果 equals 返回 true,则认为对象相同。

        每当您在方法中实现 equals 时,您还必须实现 HashCode,并且您需要遵循关于这两种方法的行为的约定。如果您不喜欢 HashMap、HashSet 等都具有未定义和不正确的行为。

        详细解释可以看这里:http://www.programcreek.com/2011/07/java-equals-and-hashcode-contract/

        Netbeans(和大多数其他 IDE)能够为您自动生成等号和哈希码方法。只需转到源->插入代码->等于和哈希码

        然后您可以选择要包含的字段,它会为您正确生成这两种方法。

        【讨论】:

          【解决方案5】:

          如果是equals(),则它是重复的,否则不是。如果您想确保它执行您想要的操作,请覆盖 equals() 方法。

          您还必须覆盖hashCode 方法,因为HashSet 在内部使用HashMap。如果你使用像 Eclipse 这样的工具,你可以很容易地使用它来生成两者。

          【讨论】:

            【解决方案6】:

            Hashset 和 HashMap 内部调用两个方法来检查是否相等。

            首先它检查 if 对象已经在桶中的 HashCode,它将使用 equals 方法检查是否相等。

            在您的情况下,您已经覆盖了 equals 方法但忘记覆盖 Hashcode。

            @Override
            public int hashCode(){
             return "Hash"+ this.name.hashCode();
            }
            

            这会给你正确的结果。

            【讨论】:

              猜你喜欢
              • 2011-12-28
              • 2012-07-05
              • 2011-08-23
              • 2012-12-05
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多