aMiGo
aMiGo

Reputation: 767

'equals()' returns false, yet object is found in map

I was messing around with some hashCode + equals + Map stuff and found something ... weird.

The snippet is as follows:

class Obj {
    String n;
    Obj(String n) {this.n = n;}

    public int hashCode() {return 0;}
    public boolean equals(Object o) {return false;} // no instance of this class 
                                                    // equals any other instance

}

Then I did something like this:

    java.util.Map<Obj,String> map = new java.util.HashMap<Obj,String>();
    Obj o1 = new Obj("1");
    Obj o11 = new Obj("1");
    Obj o2 = new Obj("2");

    map.put(o1,"val 1");
    map.put(o11,"val 2");
    map.put(o2,"val 3");

    p("size = " + map.size()); // obviously 3
    p(map.get(new Obj("1"))); // obviously null     
    p(map.get(o1)); // ...

The last line is the weird part. The last line returns val 1. How come? The equals method always returns false. Is this because the == operator is used before equals is called?

Thanks for any insight.

Upvotes: 8

Views: 2202

Answers (2)

101100
101100

Reputation: 2716

In HashMap.java, the get method is:

public V get(Object key) {
    if (key == null)
        return getForNullKey();
    int hash = hash(key.hashCode());
    for (Entry<K,V> e = table[indexFor(hash, table.length)];
         e != null;
         e = e.next) {
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
            return e.value;
    }
    return null;
}

The line if (e.hash == hash && ((k = e.key) == key || key.equals(k))) does indeed compare the keys using == before calling equals. That is why your attempt to eliminate equality fails.

Upvotes: 9

Hurda
Hurda

Reputation: 4715

The hash map implementation checks both for == and equals equality of the keys. (In case that hashCode is the same)

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/HashMap.java#HashMap.get%28java.lang.Object%29

Upvotes: 2

Related Questions