Nizam
Nizam

Reputation: 623

Little Confusion Over Hashing

Consider ther following code :

public class CarEqualsTestAgain {

String model;

    public CarEqualsTestAgain(String x) {
        this.model=x;
    }

    @Override
    public int hashCode(){               //bad hashcode
        System.out.println("__hash__");
        return 1;
    }

    @Override
    public boolean equals(Object o){
        System.out.println("In equals");
        if((o instanceof CarEqualsTestAgain) && ((CarEqualsTestAgain)o).model==this.model){
            return true;
        }
        else
            return false;
    }

    public static void main(String[] args) {

        Map map=new HashMap();

        CarEqualsTestAgain car1=new CarEqualsTestAgain("8");
        map.put(car1, "Red");
        System.out.println("Key1 : "+map.get(car1));         //Line 1

        CarEqualsTestAgain car2=new CarEqualsTestAgain("8");
        System.out.println("Key2 : "+map.get(car2));         //Line 2

        CarEqualsTestAgain car3=car1;
        System.out.println("Key3 : "+map.get(car3));         //Line 3

        CarEqualsTestAgain car4=new CarEqualsTestAgain("9");
        map.put(car4, "Red");
        System.out.println("Key4 : "+map.get(car4));         //Line 4

        CarEqualsTestAgain car5=new CarEqualsTestAgain("10");
        map.put(car5, "Red");
        System.out.println("Key5 : "+map.get(car5));          //Line 5

        CarEqualsTestAgain car6=new CarEqualsTestAgain("8");
        map.put(car6, "Green");
        System.out.println("Key6 : "+map.get(car6));          //Line 6

        key=(String)map.get(car1);
        System.out.println("Key1 : "+key);                    //Line 7

    }

}

Prints output as:

__hash__
__hash__
Key1 : Red

__hash__
In equals
Key2 : Red

__hash__
Key3 : Red

__hash__
In equals
__hash__
Key4 : Red

__hash__
In equals
In equals
__hash__
Key5 : Red

__hash__
In equals
In equals
In equals
__hash__
In equals
In equals
In equals
Key6 : Red

__hash__
In equals
In equals
Key1 : Green

My Question is :

1) When each Object is created JVM calculate its hashcode and put it in bucket or When Hashmap put() method is called then only JVM uses key Object to calculate hashcode ?

2) put() and get() calls both hashcode and equals method. Hence put() method calls overrided equals() correctly depending upon the no. of objects in bucket as seen in output for Line 1,4,5,6. But for get() method it is not the same. For Line 1 get() doesn't call equal(), Line 2 did, Line 3,4,5 didn't call, Line 6 did. Line 7 didn't WHY?

3) equals(Object o) method compares the passed object i.e Object o with all Objects resides in bucket with given hashcode. Then why did it doesn't stop comapring when it found one early. Ex - Say in bucket 1928 car1 car4 car5 resides, so when car6 calls get() which calls equals() then if car6 compares with car1 and found to be equal then it should stop comparing, but instead it compares 3 times. WHY?

Upvotes: 0

Views: 103

Answers (1)

Jon Skeet
Jon Skeet

Reputation: 1503799

When each Object is created JVM calculate its hashcode and put it in bucket or When Hashmap put() method is called then only JVM uses key Object to calculate hashcode ?

It only calls hashCode() when it needs to - in this case when you call put() or get().

For Line 1 get() doesn't call equal(), Line 2 did, Line 3,4,5 didn't call, Line 6 did. Line 7 didn't WHY?

You're getting confused by your own diagnostics. This call:

System.out.println("Key1 : "+map.get(car1)); 

is equivalent to:

Object tmp = map.get(car1);
System.out.println("Key1 : " + tmp);

So the call to equals occurs before you print Key1. To make it simpler to understand, you should change your diagnostics to:

System.out.println("Test 1");
CarEqualsTestAgain car1 = new CarEqualsTestAgain("8");
System.out.println("Created car");
map.put(car1, "Red");    
System.out.println("Added car to map");
Object tmp = map.get(car1);
System.out.println("Result of get: " + tmp);

That way it's clearer what happens when. In general, both put() and get() need to:

  • Call hashCode() on the key you're adding/fetching
  • If that hash code matches existing ones in the map, call equals() for each match, until either it runs out of matches or finds an equal object

3) equals(Object o) method compares the passed object i.e Object o with all Objects resides in bucket with given hashcode. Then why did it doesn't stop comapring when it found one early. Ex - Say in bucket 1928 car1 car4 car5 resides, so when car6 calls get() which calls equals() then if car6 compares with car1 and found to be equal then it should stop comparing, but instead it compares 3 times. WHY?

You're assuming that it compares with car1 first. Hash maps are effectively unordered - there's no guarantee which order candidates with equal hash codes will be compared in. It will stop when it finds a match though. If you change your hash code to be more sensible, it's very likely that it will only need to check one item.

Upvotes: 1

Related Questions