我有一个类“Accumulator”,它实现了 Comparable compareTo 方法,我试图将这些对象放入一个 HashSet 中。
当我 add() 到 HashSet 时,我在调试器中的 compareTo 方法中看不到任何活动,无论我在哪里设置断点。此外,当我完成 add()s 时,我在 Set 中看到了几个重复项。
我在这里搞砸了什么;为什么不比较,因此允许欺骗?
谢谢,
IVR 复仇者
我有一个类“Accumulator”,它实现了 Comparable compareTo 方法,我试图将这些对象放入一个 HashSet 中。
当我 add() 到 HashSet 时,我在调试器中的 compareTo 方法中看不到任何活动,无论我在哪里设置断点。此外,当我完成 add()s 时,我在 Set 中看到了几个重复项。
我在这里搞砸了什么;为什么不比较,因此允许欺骗?
谢谢,
IVR 复仇者
我在这里搞砸什么?
HashSet 基于hashCode()
,而不是compareTo()
。您可能会将其与TreeSet
. 在这两种情况下,请务必以equals()
与另一种方法一致的方式实施。
您需要正确实施hashCode()
和equals()
.
您必须根据类中的值覆盖hashCode
并返回一个数字,以便任何两个相等的对象具有相同的哈希码。
HashSet 使用hashCode()
和equals()
方法来防止添加重复项。首先,它获取您要添加的对象的哈希码。然后,它为该哈希码找到相应的存储桶,并遍历该存储桶中的每个对象,使用该equals()
方法查看集合中是否已经存在任何相同的对象。
您的调试器没有中断,compareTo()
因为它从未与HashSet
!
规则是:
如果两个对象相等,那么它们的哈希码 必须相等。
但是如果两个对象的哈希码相等,那么这并不意味着对象相等!这可能是两个对象恰好具有相同的哈希值。
当 hashCode 为 2 个对象返回不同的值时,不使用 equal。顺便说一句,compareTo 与散列集合无关 :) 但排序集合
您的对象是Comparable
,并且可能您也已经实现equals()
了,但是要HashSets
处理对象哈希,并且您可能还没有实现hashCode()
(或者您的实现hashCode()
不会为(a.equals(b) == true)
.
人们倾向于忽略的一件事会导致巨大的错误。在定义 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 方法将永远不会被调用。
希望这可以帮助
HashSet 使用 hashCode 和 equals。TreeSet 使用 Comparable 接口。注意:如果您决定覆盖 hashcode 或 equals,则应始终覆盖另一个。
当您创建Accumulator类的对象时,它会在JVM中占用新空间,并且每次在hashSet中添加对象时都会返回唯一的hashCode。它不依赖于对象的值,因为您没有覆盖hashCode()方法,因此它将调用Object类hashCode()方法,该方法将返回唯一的 hashCode 以及在程序中创建的每个对象。
解决方案:
覆盖hashCode()和equals()方法并根据类的属性应用您的逻辑。请务必阅读 equals 和 hashcode 合约
http://www.ibm.com/developerworks/java/library/j-jtp05273/index.html