2

I had a very basic doubt with respect to Java HashMap when duplicate keys are being inserted.

My intention is to create 4 Emp objects. 2 Objects (e1 and e2) have the same hashCode. So when inserting the e1 (which is being inserted after e2), hashmap would realize that an object with the same hash value is already present (object e2). It will then compare the keys of all objects in the slot with the same hash value. If it finds an object with matching key (by calling the equals method of the Emp class below), it will replace the old value with the new one.

Please have a look at the test code below:

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

class Emp {
        String name;
        int age;

        public Emp(String name, int age) {
                this.name = name;
                this.age = age;
        }

        public boolean equals(Object s) {
                if(s instanceof Emp) {
                        Emp s1 = (Emp) s;
                        return ((s1.name.compareToIgnoreCase(this.name) == 0));
                }
                return false;
        }

        public int hashCode() {
                //return (this.name.hashCode() + this.age);
                return this.name.hashCode();
        }
}

public class HashTest {
        public static void main(String[] args) {
                Emp e1 = new Emp("Terry", 26);
                Emp e2 = new Emp("Terry" , 60);
                Emp e3 = new Emp("John", 21);
                Emp e4 = new Emp("Test", 60);

                Map<Emp,Emp> emp = new HashMap<Emp, Emp>();
                emp.put(e2,e2);
                Emp v2 = emp.put(e1,e1);
                emp.put(e3,e3);
                emp.put(e4,e4);

                System.out.println("Replaced Record Name: " + v2.name + " , age: " + v2.age);
                for(Emp e: emp.keySet())
                        System.out.println("Name: " + e.name + " , age: " + e.age);
        }
}

The output I was expecting: Replaced Record Name: Terry , age: 60 Name: Test , age: 60 Name: Terry , age: 26 Name: John , age: 21

The output I got: Replaced Record Name: Terry , age: 60 Name: Test , age: 60 Name: Terry , age: 60 Name: John , age: 21

I was expecting (Terry, 60) to be replaced by (Terry, 26) object. This seems to be happening as i get Replaced Record Name: Terry , age: 60 as output. However, the map contains the record Name: Terry , age: 60 instead of Name: Terry , age: 26.

Edit: Thanks everyone for the suggestion. It turns out I was making a very careless mistake. Instead of printing the values associated with a key, I was printing only the key.

As everyone has pointed out, the solution is to:

  for(Emp e: emp.keySet())
  {
        Emp empVal = emp.get(e);
        System.out.println("Name: " + empVal.name + " , age: " + empVal.age);
  }

3 Answers 3

2

Your output is printing the keys, not the values. In your code the key will not change but the value will.

For instance, if you change your output loop to:

for (Emp emp : emp.values()) {
  System.out.println("Name: " + e.name + " , age: " + e.age);
}

I suspect you'll see the answer you were expecting.

However: In general I would advise against doing what you're doing here. All kinds of code expects that if a.equals(b) then a and b don't have any meaningful differences at all, and your Emp class's equals implementation doesn't live up to that contract. For instance, if you used a HashSet rather than a HashMap you would get much more peculiar behavior and there'd be no way to fix it.

A better way to implement this might be to have Emp's hashCode and equals methods properly respect name and age, and make your map be a Map<String, Emp> where the key is the employee's name and the value is the Emp record.

Sign up to request clarification or add additional context in comments.

1 Comment

jacobm thanks for the good catch. I was breaking my head on this for so long.. hate careless mistakes :(
0

I have slightly amended your code - see below. The new value is put in the map, but since the keys are equals, the second put reuses the existing key.

public static void main(String[] args) {
    Emp e1 = new Emp("Terry", 26);
    Emp e2 = new Emp("Terry", 60);

    Map<Emp, Emp> emp = new HashMap<Emp, Emp>();
    emp.put(e2, e2);
    Emp v2 = emp.put(e1, e1);

    System.out.println("Replaced Record Name: " + v2.name + " , age: " + v2.age);
    for (Emp e : emp.keySet()) {
        System.out.println("[key] Name: " + e.name + " , age: " + e.age);
        System.out.println("[value] Name: " + emp.get(e).name + " , age: " + emp.get(e).age);
    }
}

Output:

[key] Name: Terry , age: 60
[value] Name: Terry , age: 26

Comments

0

In the below statement you are actually printing keys.. By calling keySet(), you get a Set of keys in the map, and you iterating over those keys and printing them.. You need to fetch values for those keys from map and print them.. So, Change the below statement: -

System.out.println("Name: " + e.name + " , age: " + e.age);

with : -

System.out.println("Name: " + emp.get(e).name + " , age: " + emp.get(e).age);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.