Java - TreeSet和hashCode()

23
我有一个关于TreeSet集合和hashCode方法的问题。我有一个TreeSet,我正在向其中添加对象,在添加对象之前,我使用contains方法检查它是否存在于TreeSet中。
我有两个不同的对象,每个对象都使用我的实现的hashCode方法产生一个不同的hashCode,例如下面的例子:
public int hashCode()
{
    int hash = 7;
    hash = hash * 31 + anAttribute.hashCode();
    hash = hash * 31 + anotherAttribute.hashCode();
    hash = hash * 31 + yetAnotherAttribute.hashCode();
    return hash;
}

一个特定运行的哈希码为:76126352和76126353(这些对象只在一个属性中的一位数字上有所不同)。

即使哈希码不同,contains方法仍然返回这些对象的真值。有任何想法为什么会这样吗?这真的很困惑,需要帮助。

4个回答

52

TreeSet不使用hashCode。它使用compareTo或者你在构造函数中传递的Comparator。这个用于像contains这样的方法来查找集合中的对象。

所以你问题的答案是,你的compareTo方法或者你的Comparator定义了两个相关的对象应该被视为相等。

从javadoc上可以看到:

一个TreeSet实例使用他的compareTo (或compare) 方法执行所有元素的比较。因此,通过该方法确定相等的两个元素,在set角度上被视为相等。


它还使用equals方法,因此equals和Comparator/compareTo的一致性非常重要。 - Dan Dyer
2
这是因为Set接口是基于equals操作定义的,但TreeSet实例使用其compareTo(或compare)方法执行所有元素比较... - Dirk
1
这就是问题所在了,我添加了一个额外的属性,更新了equals和hashCode,但忘记了compareTo。谢谢! - Gaz
如果我在TreeSet中插入一个Integer对象,即使已经存在一个具有相同值的Integer,contains()方法返回false会怎么样? - Nitish Upreti

4

来自Java文档:

如果两个对象根据equals(Object)方法是相等的,则在这两个对象中调用hashCode方法必须产生相同的整数结果。

意思是:您用于哈希的对象不相等。


1
这是在假设已经以不违反这个规约的方式定义了hashCode和equals的情况下。 - sepp2k
2
@sepp2k 这是hashCode()的“通用契约”。这就是为什么它使用“必须”一词的原因。 - user207421

0

你不需要检查它是否已包含,因为insert()基本上会执行相同的操作(即在插入点搜索适当位置)。如果无法插入对象(即对象已经存在),insert将返回false。


这是一个非常干净简洁的API的例子(就像大多数集合类一样)。 - helpermethod

0
你需要阅读乔舒亚·布洛赫(Joshua Bloch)的《Effective Java》第3章。该章节解释了equals合约以及如何正确地重写equals、hashCode和compareTo方法。

它甚至可以在线获取:http://java.sun.com/developer/Books/effectivejava/Chapter3.pdf - gustafc
我本来准备给gustafc的评论点赞,但是链接现在已经失效了 :( - Matthew Gilliard
去买那本书吧,它仍然在那里。 - duffymo

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