HashSet问题 -- equals和hashCode与contains的作用不同于我的预期

3

I have the following code:

class IncidentTag:
     def __init__(self,tag):
        self.tag = tag
     def equals(self,obj):
        return self.tag.equals(obj.tag)
     def hashCode(self):
        return self.tag.hashCode()

from java.lang import String
from java.util import HashMap
from java.util import HashSet

tag1 = IncidentTag(String("email"))
tag1copy = IncidentTag(String("email"))
tag2 = IncidentTag(String("notemail"))

print tag1.equals(tag1copy)
print tag2.equals(tag2)

print "Now with HashSet:"

hSet = HashSet()
hSet.add(tag1)
hSet.add(tag2)

print hSet.contains(tag1)
print hSet.contains(tag2)
print hSet.contains(tag1copy)

输出结果如下: 1 1 现在使用HashSet: 1 1 0
然而,我本来期望最后一行也是true(1)。我是否漏掉了什么明显的问题?
(是的,我知道我的equals方法和hashcode方法没有考虑到一些问题...它们故意简单,但如果这些问题导致了这个问题,请告诉我。)
3个回答

10

你不应该实现Java风格的equals和hashCode方法,而是使用Python中对应的__eq____hash__方法。添加

def __hash__(self):
    return self.hashCode()
def __eq__(self, o):
    return self.equals(o)

这些 Python 方法 - 就我所知 - 由 Jython 动态绑定到 hashCode 和 equals()。这确保您可以将 Python 类放入 Java 的集合中。

现在该代码打印出五个“1”。


这很奇怪。我猜语言绑定就是这样,但我没有在任何地方看到过这个文档。不管怎样,这确实解决了问题...谢谢! - jsight

1

我在Java中编写了等效的代码,并且它对所有三个contains()调用都产生了true。因此,我认为这必须是Jython中的奇怪现象。也许Python中看到的底层Java对象并不完全是它们看起来的样子。


我也用Java写了同样的代码 - 并且得到了与Dave Costa相同的结果。 - matt b

0

我不懂Python,但是看起来底层的Java对象的equals()和hashcode()没有遵守必要的协议。

  • 如果equals()返回true,则两个对象必须返回相同的hashcode()。

看起来这个规则被违反了。HashSet首先会使用hashcode进行查找以获取匹配对象所在的列表,然后遍历列表以找到相等的对象。如果你的hashcode没有遵守协议并且返回不同的hashcode,那么即使它们是equals()可比较的,它也无法在hashset中找到。

默认的Java Object.hashcode()不会为2个对象返回相同的hashcode。你需要重写它。


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