Question

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)

The output is: 1 1 Now with HashSet: 1 1 0

However, I would have expected the last line to be true (1) as well. Is there something obvious that I am missing.

(yes, I know that my equals method and hashcode methods do not take some issues into account... they are deliberately simple, but do let me know if the issues there are causing this problem)

Was it helpful?

Solution

You shouldn't implemented the Java-Style equals and hashCode method, but instead the Python equivaltents __eq__ and __hash__. Adding

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

helps. These python methods are - as far as I know - dynamically bound to hashCode and equals() by Jython. This ensures that you can put Python classes into Java's collections.

Now the code prints five "1".

OTHER TIPS

I wrote equivalent code in Java and it does produce true for all three contains() calls. So I think this must be an oddity in Jython. Maybe the underlying Java objects are not exactly what you see them as in Python.

I don't know Python, but it sure looks like the underlying Java object's equals() and hashcode() aren't honoring the required contract.

  • Two objects if equals() must return the same hashcode().

It looks like that is violated. HashSets are first going to use the hashcode in the lookup to get the list the matching object would be in, then go through the list to find the one that's equal. If your hashcode isn't honoring the contract and they're returning different hashcodes, then it won't find it in the hashset even if they were equals() comparable.

The default Java Object.hashcode() isn't going to return the same hashcode for 2 objects. You've got to override it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top