HashSet问题 - equals和hashCode包含的工作方式与我预期的不同

时间:2008-10-23 17:16:39

标签: java collections jython hashset

我有以下代码:

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

但是,我原本期望最后一行也是真的(1)。是否有一些我遗漏的明显事物。

(是的,我知道我的equals方法和hashcode方法没有考虑到一些问题......它们是故意简单的,但如果问题导致这个问题,请告诉我)

3 个答案:

答案 0 :(得分: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”。

答案 1 :(得分:1)

我在Java中编写了等效的代码,它确实为所有三个contains()调用生成了true。所以我认为这在Jython中一定是个怪人。也许底层的Java对象并不像你在Python中看到的那样。

答案 2 :(得分:0)

我不知道Python,但它确实看起来像底层Java对象的equals()和hashcode()没有遵守所需的合同。

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

看起来违反了这一点。 HashSets首先在查找中使用哈希码来获取匹配对象所在的列表,然后通过列表找到相同的列表。如果您的哈希码不遵守合同并且它们返回不同的哈希码,那么即使它们与equals()相当,它也不会在哈希集中找到它。

默认的Java Object.hashcode()不会为2个对象返回相同的哈希码。你必须覆盖它。