2

I implemented the overriding equals and hashCode correctly. In the code below when I print out map and num1, I can see in the console that they both have the updated hashCode(). But when I try to get it out of the map, it says it’s null. Can some one help explain why .get() method cannot find it?

class Phone {

    int number;

    Phone(int number) {this.number = number;}

    public int hashCode() {
        return number;
    }

    public boolean equals(Object o) {
        if (o != null && o instanceof Phone)
            return (number == ((Phone)o).number);
        else
            return false;
    }

    public static void main(String args[]) {
        Map<Phone, String> map = new HashMap<>();
        Phone num1 = new Phone(2500);
        map.put(num1, "John");
        num1.number = 100;

        System.out.println(map);
        System.out.println(num1);
        System.out.println(map.get(num1)); // why does it print null
    }
}
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
tupaje
  • 51
  • 1
  • 3
  • notice `num1.number = 100;` – Ramanlfc Mar 17 '16 at 19:01
  • Fellow developers: This is not a bad question and is likely a very common mistake that can be made. You should upvote this question as it may be helpful for others. – pczeus Mar 17 '16 at 19:09
  • @pczeus It probably got downvoted because it is a common question and there are multiple answered questions on the site already (the question I linked above probably was already suggested when the title of this question was entered). – Mark Rotteveel Mar 17 '16 at 19:11

2 Answers2

2

It returns null, because you have changed the number of num1 object, thus changing it hashcode. Hash map uses hashcode() to store and retrieve objects, so when you change it, you then look for an object on a wrong place, since it is stored on place numbered 2500, but then you look it on place 100. That's because your hashcode returns the number. Hope this helps.

Nikolay Tomitov
  • 947
  • 5
  • 12
2

You have created an issue because you modified the key after placing it into the Map, which get's hashed from your hashcode method, based off of number.

Cleaning up you code a bit. More specifically, making number immutable and only giving access to number via a public getter method. You should not allow key's in a Map to be mutable.

public class MyNumber {
    private int number;

    public MyNumber(int number) {
        this.number = number;
    }

    public int getNumber(){
        return number;
    }

    @Override
    public int hashCode() {
        return number;
    }

    @Override
    public boolean equals(Object o) {
        if (o != null && o instanceof MyNumber) {
            return (number == ((MyNumber) o).number);
        }
        else {
            return false;
        }
    }

    @Override
    public String toString(){
        return this.getClass().getName() + "(" + number + ")";
    }
}

I have added comments to the code within your main class:

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

public class OverrideHashCode {

    public void mutableObjectKeys() {
        Map<MyNumber, String> map = new HashMap<>();
        MyNumber num1 = new MyNumber(2500);
        map.put(num1, "Shreya");

        System.out.println(map);
        System.out.println(num1);

       //This line was your issue. You placed the MyNyumber in the map
        //The hashcode pulls the number value from MyNumber to hash the entry (2500 )
        //Then you change the value of number
        //num1.getNumber() = 100;
        System.out.println(map);
        System.out.println(num1);

        //This was hashed at 2500, but you changed the MyNumber to 100 - no match
        System.out.println(map.get(num1)); // prints null - not anymore

        //Let's put a second object in the Map
        map.put(new MyNumber(500), "GroovyIsBetter!");

        //When you work with Maps, you are commonly trying to get values out of the map based on the key.
        //In this example, our key's are MyNumber(s)
        //We have made MyNumber.number immutable (which is good).
        //Because you implemented your own hashcode and equals, you can even pull the value out of the map
       //with a new MyNumber object that has the same number value as the original key you placed in the map
        System.out.println("\n" + map.get(new MyNumber(2500)));
        System.out.println(map.get(new MyNumber(500)));

        //Now we can remove one of the keys and recheck
        //Should come up null
        map.remove(new MyNumber(500));
        System.out.println(map.get(new MyNumber(500)));
    }

    public static void main(String... args){
        new OverrideHashCode().mutableObjectKeys();;
    }
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
pczeus
  • 7,709
  • 4
  • 36
  • 51