Проблема с HashSet — равенства и hashCode с содержанием работают не так, как я ожидал
-
04-07-2019 - |
Вопрос
У меня есть следующий код:
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() по умолчанию не будет возвращать один и тот же хэш-код для двух объектов.Вы должны переопределить это.