Java HashSet允许重复项;与Comparable有关的问题?

9
我有一个类"Accumulator",它实现了Comparable compareTo方法,我正在尝试将这些对象放入HashSet中。
当我添加到HashSet时,在调试器中无论我在哪里设置断点,都看不到compareTo方法的任何活动。此外,当我完成添加后,在Set中看到几个重复项。
我在这里搞砸了什么,为什么它没有进行比较,因此允许重复项?
谢谢, IVR Avenger
8个回答

17

我在这里搞砸了什么?

HashSet基于hashCode(),而不是compareTo()。您可能与TreeSet混淆了。 在两种情况下,一定要以与其他方法一致的方式实现equals()


11

你需要正确实现hashCode()equals()

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


没有等号的话,它将完全无效。 - Justin

6
HashSet使用hashCode()equals()方法来防止重复添加。首先,它获取要添加的对象的哈希码。然后,找到相应的并迭代该桶中的每个对象,使用equals()方法查看集合中是否已经存在任何相同的对象。
您的调试器不会在compareTo()上停止,因为它从未与HashSet一起使用!
规则如下:
  1. 如果两个对象相等,则它们的哈希码必须相等。

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


2

人们经常忽略的一个事情会导致巨大的错误。 在定义equals方法时,始终将参数作为对象类,并将对象转换为所需的类。 例如:

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

如果你传递的是写有 Song 的 Song 对象而不是 Object aSong,那么你的 equals 方法将永远不会被调用。
希望这可以帮到你。

2

当两个对象的 hashCode 返回不同的值时,equal 方法将不会被使用。另外,compareTo 方法与哈希集合无关,但是与排序集合有关。


2

您的对象是Comparable,可能已经实现了equals()方法,但是HashSets处理对象哈希值,很有可能您没有实现hashCode()方法(或者您实现的hashCode()方法对于两个满足(a.equals(b) == true)的对象返回的哈希值不同)。


1

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


1
只有在重写equals方法(定义为相等性已更改)时才需要重写hashCode方法。反之则不一定成立。将hashCode更改为返回1并保持equals不变是完全合法的。 - Steve Kuo

1
每当你创建一个Accumulator类的对象时,它会在JVM中占用新的内存空间,并且每次将对象添加到hashSet中都会返回唯一的hashCode。这并不取决于对象的值,因为你没有重写hashCode()方法,所以它将调用Object类的hashCode()方法,该方法将为程序中创建的每个对象返回唯一的hashCode

解决方案:

重写hashCode()equals()方法,并根据你的类的属性应用适当的逻辑。务必阅读equalshashCode的合同。

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


提供的链接非常有帮助,对于像我这样的初学者来说非常实用。 - user1918715

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接