9

我有一个类“Accumulator”,它实现了 Comparable compareTo 方法,我试图将这些对象放入一个 HashSet 中。

当我 add() 到 HashSet 时,我在调试器中的 compareTo 方法中看不到任何活动,无论我在哪里设置断点。此外,当我完成 add()s 时,我在 Set 中看到了几个重复项。

我在这里搞砸了什么;为什么不比较,因此允许欺骗?

谢谢,
IVR 复仇者

4

8 回答 8

17

我在这里搞砸什么?

HashSet 基于hashCode(),而不是compareTo()。您可能会将其与TreeSet. 在这两种情况下,请务必以equals()与另一种方法一致的方式实施。

于 2010-06-02T20:30:44.780 回答
11

您需要正确实施hashCode()equals().

您必须根据类中的值覆盖hashCode并返回一个数字,以便任何两个相等的对象具有相同的哈希码。

于 2010-06-02T20:30:13.947 回答
6

HashSet 使用hashCode()equals()方法来防止添加重复项。首先,它获取您要添加的对象的哈希码。然后,它为该哈希码找到相应的存储桶,并遍历该存储桶中的每个对象,使用该equals()方法查看集合中是否已经存在任何相同的对象。

您的调试器没有中断,compareTo()因为它从未与HashSet!

规则是:

  1. 如果两个对象相等,那么它们的哈希码 必须相等。

  2. 但是如果两个对象的哈希码相等,那么这并不意味着对象相等!这可能是两个对象恰好具有相同的哈希值。

于 2010-06-02T20:53:12.677 回答
2

当 hashCode 为 2 个对象返回不同的值时,不使用 equal。顺便说一句,compareTo 与散列集合无关 :) 但排序集合

于 2010-06-02T20:31:32.597 回答
2

您的对象是Comparable,并且可能您也已经实现equals()了,但是要HashSets处理对象哈希,并且您可能还没有实现hashCode()(或者您的实现hashCode()不会为(a.equals(b) == true).

于 2010-06-02T20:34:48.163 回答
2

人们倾向于忽略的一件事会导致巨大的错误。在定义 equals 方法时,始终将参数作为对象类,然后将对象转换为所需的类。例如

   public bolean equals(Object aSong){
     if(!(aSoneg instanceof Song)){
       return false;
     }
     Song s=(Song) aSong;
     return getTitle().equals(s.getTitle());
   }

如果你通过 write Song aSong 而不是 Object aSong 你的 equals 方法将永远不会被调用。

希望这可以帮助

于 2013-04-04T19:49:06.520 回答
1

HashSet 使用 hashCode 和 equals。TreeSet 使用 Comparable 接口。注意:如果您决定覆盖 hashcode 或 equals,则应始终覆盖另一个。

于 2010-06-02T20:31:09.350 回答
1

当您创建Accumulator类的对象时,它会在JVM中占用新空间,并且每次在hashSet中添加对象时都会返回唯一的hashCode。它不依赖于对象的值,因为您没有覆盖hashCode()方法,因此它将调用ObjecthashCode()方法,该方法将返回唯一的 hashCode 以及在程序中创建的每个对象。

解决方案:

覆盖hashCode()equals()方法并根据类的属性应用您的逻辑。请务必阅读 equals 和 hashcode 合约

http://www.ibm.com/developerworks/java/library/j-jtp05273/index.html

于 2012-12-14T07:45:52.797 回答