Проблема с HashSet — равенства и hashCode с содержанием работают не так, как я ожидал

StackOverflow https://stackoverflow.com/questions/230585

Вопрос

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

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 Теперь с хэшсом:1 1 0

Однако я ожидал, что последняя строка тоже будет правдой (1).Есть ли что-то очевидное, чего мне не хватает?

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

Это было полезно?

Решение

Вам не следует реализовывать методы равенства и hashCode в стиле Java, а вместо этого использовать эквиваленты Python. __eq__ и __hash__.Добавление

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

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

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

Другие советы

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top