Проблема HashSet - equals и hashCode с содержимым работают иначе, чем я ожидал - PullRequest
3 голосов
/ 23 октября 2008

У меня есть следующий код:

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 и методы хэш-кода не принимают во внимание некоторые проблемы ... они преднамеренно просты, но дайте мне знать, если проблемы там вызывают эту проблему)

Ответы [ 3 ]

10 голосов
/ 23 октября 2008

Вы не должны реализовывать Java-стиль equals и hashCode, а вместо этого Python равнозначен __eq__ и __hash__. Добавление

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

помогает. Эти методы Python, насколько я знаю, динамически связаны с hashCode и equals () в Jython. Это гарантирует, что вы можете помещать классы Python в коллекции Java.

Теперь код печатает пять «1».

1 голос
/ 23 октября 2008

Я написал эквивалентный код на Java, и он выдает true для всех трех вызовов contains () Поэтому я думаю, что это должно быть странностью в Jython. Возможно, лежащие в основе объекты Java не совсем такие, какими вы их видите в Python.

0 голосов
/ 24 октября 2008

Я не знаю Python, но, похоже, похоже, что лежащие в основе Java объекты equals () и hashcode () не выполняют требуемый контракт.

  • Два объекта, если они равны (), должны возвращать один и тот же хэш-код ().

Похоже, это нарушено. HashSets сначала использует хеш-код в поиске, чтобы получить список, в котором будет найден соответствующий объект, затем просмотрите список, чтобы найти тот, который равен. Если ваш хэш-код не выполняет контракт, и они возвращают разные хеш-коды, то он не найдет его в хэш-наборе, даже если они были сопоставимы с равными ().

Java Object.hashcode () по умолчанию не собирается возвращать один и тот же хеш-код для 2 объектов. Вы должны переопределить это.

...