开发者

Can you explain this Java hash map key collision?

开发者 https://www.devze.com 2023-01-27 19:52 出处:网络
I have a HashMap and is used in the following way: HashMap<SomeInterface, UniqueObject> m_map; UniqueObject getUniqueObject(SomeInterface keyObject)

I have a HashMap and is used in the following way:

HashMap<SomeInterface, UniqueObject> m_map;

UniqueObject getUniqueObject(SomeInterface keyObject)
{
     if (m_map.containsKey(keyObject))
     {
         return m_map.get(keyObject);
     }
     else
     {
         return makeUniqueObjectFor(keyObject);
     }
}

My issue is that I'm seeing multiple objects of different classes matching the same key on m_map.containsKey(keyObject).

So here are my questions:

  1. Is this possible? The Map interface says it uses equals() to compare if the key is not null. I haven't overridden equals() in any of my SomeInterface classes. Does this mean the equals method can be wrong?

  2. If the above is true, how do I get HashMap to only return true on equals() if they are in fact the same object and not a copy? Is this possible by saying if (object1 == object2)? I was told early on in 开发者_Go百科Java development that I should avoid doing that, but I never found out when it should be used.

Thanks in advance. :)


I strongly suspect you've misdiagnosed the issue. If you aren't overriding equals anywhere (and you're not subclassing anything else that overrides equals) then you should indeed have "identity" behaviour.

I would be shocked to hear that this was not the case, to be honest.

If you can product a short but complete program which demonstrates the problem, that would make it easier to look into - but for the moment, I'd definitely double-check your suspicions about seeing different objects being treated as equal keys.


The default implementation of equals() is done in java.lang.Object:

public boolean equals(Object obj) {
return (this == obj);
}

Other method hashCode(); by default returns some kind of reference to the object. I.e. both are unique by default. Equals returns true only for the same object, hashCode() is different for every object.

This is exactly what can create some kind of multiple entries. You can create 2 instances of your class. From your point of view they are equal because they contain identical data. But they are different. So, if you are using these objects as keys of map you are producing 2 entries. If you want to avoid this implement equals and hashCode for your class.

This implementation sometimes is very verbose. HashCodeBuilder and EqualsBuilder from Jakarta project may help you. Here is an example:

@Override
public int hashCode() {
    return HashCodeBuilder.reflectionHashCode(this);
}

@Override
public boolean equals(Object other) {
    return EqualsBuilder.reflectionEquals(this, other);
}

@Override
public String toString() {
    return ToStringBuilder.reflectionToString(this);
}


You need to ensure that your .equals() and your .hashCode() methods are implemented for all objects that you want to store in the HashMap. To not have that invites all sorts of problems.


You must implement the equals() and hashCode() methods of the objects that you use as the keys in the HashMap.

Note that HashMap not only uses equals(), it also uses hashCode(). Your hashCode() method must be implemented correctly to match the implementation of the equals() method. If the implementation of these methods don't match, you can get unpredictable problems.

See the description of equals() and hashCode() in the API documentation of class Object for the detailed requirements.


FYI you can have IDE's such as Eclipse generate the hashCode & equals methods for you. They'll probably do a better job than if you try to hand-code them yourself.

0

精彩评论

暂无评论...
验证码 换一张
取 消