0

I am confused with below piece of code. When i changed the the name for employee e2 i was expecting the map to have both e2 and e3 objects as the e2 object is now different than e3. But it seems changing the name for e2 object is not reflected in the e2 object stored in hashmap so the output shows only e3. So i am confused whether the hashmap stores the actual object or just the copy of the original object.

Code:

import java.util.HashMap;

public class Main {

    public static void main(String[] args) {

        HashMap<Employee,Integer> map = new HashMap<Employee,Integer>();

        Employee e1 = new Employee(10,"Sachin");
        Employee e2 = new Employee(10,"Sachin");

        map.put(e1, 1);
        map.put(e2,2);

        System.out.println(e1.hashCode()+"    "+e2.hashCode());

        System.out.println(map);

        e2.setName("Akshay"); //<---- changing the name for e2

        Employee e3 = new Employee(10,"Sachin");        
        map.put(e3, 3);

        System.out.println(map);
    }
}

class Employee
{
    private int id;
    private String name;

    public Employee(int id, String name) {
        super();
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + id;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Employee other = (Employee) obj;
        if (id != other.id)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }   
}

Output:

-1826112337    -1826112337
{Employee [id=10, name=Sachin]=2}
{Employee [id=10, name=Sachin]=3}
  • 1
    When you attempt to put a value for an existing key, only the associated value is replaced. So your `put(e2, 2)` does not replace `e1` as the key. – Sotirios Delimanolis Aug 22 '18 at 15:07
  • So e1 is never replaced in hashmap but just the values is updated to 2 considering the same key . So e2 was never added in hashmap and again when i do put(e3,3) same thing happens e3 is not being added but just the value is updated to 3 – Akshay Panchakshari Aug 22 '18 at 15:21
  • That's right. It might help to add another id that isn't used in the hashcode or equals, but only for logging. – Sotirios Delimanolis Aug 22 '18 at 15:25

1 Answers1

0

As you probably know, each entry in a HashMap is allocated a bucket based on it's hashCode(). The bucket is allocated when the entry is put() in the Map (same goes for adding an item to a HashSet)

If you mutate the key after putting in a Map, the HashMap has no knowledge of this mutation. It doesn't recalculate the bucket and move the entry to a new bucket (how could it? It has no way of listening for this event)

As a rule of thumb, don't mutate a key in a Map (or an item in a Set) as you'll get unexpected behaviour for Map.containsKey(...) and Set.contains(...) etc.

lance-java
  • 25,497
  • 4
  • 59
  • 101
  • ok so the key object stored in entry is different than the actual key object? As i am mutating the key object so shouldn't be reflected in key object stored in hashmap as well if both the objects are same or points to the same memory location? – Akshay Panchakshari Aug 22 '18 at 15:07
  • 1
    This is the wrong explanation for _But it seems changing the name for e2 object is not reflected in the e2 object stored in hashmap so the output shows only e3._ – Sotirios Delimanolis Aug 22 '18 at 15:08
  • See my updates, a bucket is allocated only when the entry is added. If you subsequently change the key's hashCode() you will get unexpected behaviour as the key no longer matches the bucket – lance-java Aug 23 '18 at 07:57
  • They aren't mutating any keys that are in the `HashMap`. The object referenced by `e2` never made it in there. – Sotirios Delimanolis Aug 23 '18 at 15:42
  • Hmm... obviously eyeballed the code incorrectly – lance-java Aug 23 '18 at 20:47