0
package always.confusing;

import java.util.HashMap;
import java.util.Map;

class Dog {
public Dog(String n) { name = n; }
public String name;
public boolean equals(Object o) {
    if((o instanceof Dog) &&
            (((Dog)o).name == name)) {
        return true;
    } else {
        return false;
    }
}
public int hashCode() {return name.length(); }
}

public class QustionToaAsk {

public static void main(String[] args) {
    // TODO Auto-generated method stub
    Map<Object, Object> m = new HashMap<Object, Object>();

    Dog d1 = new Dog("clover");
    m.put(d1, "Dog key");

    System.out.println("**" + m.get(new Dog("clover")));

    d1.name = "magnolia";
    System.out.println("state after magnolia");
    System.out.println(m.get(new Dog("magnolia")));
    System.out.println(m.get(d1)); // #1
    System.out.println("**" + m.get(new Dog("clover")));///????????
    System.out.println("size:" + m.size());

    d1.name = "clover";
    System.out.println("\nstate after clover");
    System.out.println(m.get(new Dog("clover"))); // #2
    System.out.println(m.get(d1));
    System.out.println("size:" + m.size());

    d1.name = "arthur";
    System.out.println("\nstate after arthur");
    System.out.println(m.get(new Dog("arthur")));
    System.out.println(m.get(d1));
    System.out.println("size:" + m.size());
}

}

O/p:

**Dog key

state after magnolia

null

null

**null

size:1

state after clover

Dog key

Dog key

size:1

state after arthur

Dog key

Dog key

size:1

why does 1st set of prints fail to fetch for Dog objects with clover and magnolia content but in other two sets it does as expected?

ie why After trying to change to "magnolia", why next get()(still using proper object ie get(new Dog("clover")))) not able to fetch the value "Dog key"? after changing to equals.. still same output –

//ignore

user2978111
  • 23
  • 12

3 Answers3

3

You need to understand how a HashMap works.

When you put a key in a HashMap, containing N buckets, the hashCode of the key is used to find the appropriate bucket. Then each key contained in the bucket is compared, using equals(), with the added key, to know if the key is already in the map.

Similarly, when getting the value for a key, the hashCode() is first used to find the appropriate bucket, then each key in this bucket is compared with equals() to the key passed to get().

You're doing two things which you should never do when using HashMaps:

  1. Modifying the key after it has been stored in the map. This modifies its hashCode, and causes thekey to not be searched for in the appropriate bucket. A bit as if you put all red coins in a red drawer, and then repainted one of the keys to blue. Obviously, if you then search for the blue coins, you'll search them in the blue drawer, and not in the red drawer where it has been stored, since it was red initially.
  2. Implementing hashCode() using an algorithm that makes many keys have the same value. It's the case for "clover" and "arthur", which have the same length, and thus the same hashCode() given your implementation. "magnolia", on the other hand, doesn't have the same hashCode().

Given the above, you should be able to understand why your code works the way it does. Just draw what happens on paper for each operation, and you'll understand.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • but still... As I am trying to update value which corresponds to key "magnolia"(which is absent).... why "System.out.println("**" + m.get(new Dog("clover"))); " (after d1.name = "magnolia") is not fetching the value "Dog key" as I am not all touching it? – user2978111 Jun 10 '14 at 21:31
  • I think you're confusing keys and values. There is a single entry in this HashMap, and you keep modifying this key. The value of the entry is never modified: it's `"Dog key"`. Read the HashMap javadoc correctly: put takes a key as first argument, and a value as second argument. – JB Nizet Jun 10 '14 at 21:34
1

I would strongly suggest you to begin with reading how hashmap works in java

There are multiple issues here.

  1. When you invoke m.put(d1, "Dog key");, the hashCode is calculated and a bucket in the hashMap where the object will be stored is determined. The hashCode value is 6 in this case.
  2. Then you're changing the name to magnolia (and thus the hashCode to 8). HashMap tries to search for matching object, but based on hashCode, it finds out, that there is no object stored in the bucket corresponding to hashCode value = 8.
  3. Then you're changing the name back to clover, and, long story short, the object can be found.
  4. Then you're changing the name to arthur. The hashCode is 6 again and HashMap manages to find the right bucket and using equals method - find the object.

Read more about hashCode and equals: http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode%28%29.

BTW You should use equals method for comparing Strings (read http://www.javapractices.com/topic/TopicAction.do?Id=18).

Dariusz
  • 371
  • 1
  • 9
  • After trying to change to "magnolia", why next get(), still using proper object ie get(new Dog("clover"))), not able to fetch the value "Dog key"? after changing to equals.. still same output – user2978111 Jun 10 '14 at 20:02
  • @user2978111 1. Changing `==` to `equals` will not resolve issues presented here, it will only resolve future issues. 2. As I said, original object was placed in the hashmap using hashCode value of 6. After changing the name to "magnolia", the hashCode has value 8. Simplifying, HashMap searches for objects in two steps. The first step compares hashCodes. In the HashMap there is no object with hashCode value o 8, so no object is found. – Dariusz Jun 10 '14 at 20:25
  • but still... As I am trying to update value which corresponds to key "magnolia"(which is absent).... why "System.out.println("**" + m.get(new Dog("clover"))); " is not fetching the value "Dog key" as I am not all touching it? – user2978111 Jun 10 '14 at 21:08
-1

First: What do you want to do?

Second: The equals() is the first problem as it only compares references. See Here

Third: The hashCode() function for dog is missing. you should never overwrite only one of equals() and hashCode() See Here

Community
  • 1
  • 1
Dawnkeeper
  • 2,844
  • 1
  • 25
  • 41
  • Although the implementation of equals method is incorrect, in this particular example it returns correct values because of String interring mechanism in Java (http://en.wikipedia.org/wiki/String_intern_pool). – Dariusz Jun 10 '14 at 19:44