Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is equals method not called in the Hashmap?

Tags:

java

hashmap

import java.util.*;
class Dog {
    public Dog(String n) { name = n; }
    public String name;
    public boolean equals(Object o) {
        System.out.println("equals called..");
        if((o instanceof Dog) &&
                (((Dog)o).name == name)) {
            return true;
        } else {
            return false;
        }
    }
    public int hashCode() {
        System.out.println("hashCodecalled..");
        return name.length(); 
    }
}
class SampleClass {
    public static void main(String[] args) {
        Map<Object, String> m = new HashMap<Object, String>();
        Dog d1 = new Dog("clover");
        m.put(d1, "Dog key");
        d1.name ="arthur";
        System.out.println(m.get(d1));      
    }
}

In the above code, the output i get is:

hashCodecalled..
hashCodecalled..
Dog key

after i do d1.name ="arthur"

i was expecting output to be

hashCodecalled..``
hashCodecalled..
equals called..
null
like image 717
user3758749 Avatar asked Jul 02 '14 02:07

user3758749


People also ask

When equals method is called in HashMap?

HashMap uses equals() to compare the key to whether they are equal or not. If the equals() method return true, they are equal otherwise not equal. A single bucket can have more than one node, it depends on the hashCode() method. The better your hashCode() method is, the better your buckets will be utilized.

Why we override equals method in HashMap?

A HashMap is not allowed to have multiple equal keys! Not after we have overridden the equals() method on Person Class. That is the reason why we must override hashCode() method after we have overridden equals method.

What will happen if equals method is not overridden in HashMap?

You must override hashCode in every class that overrides equals. Failure to do so will result in a violation of the general contract for Object. hashCode, which will prevent your class from functioning properly in conjunction with all hash-based collections, including HashMap, HashSet, and Hashtable.

Why we need to override hashCode and equals method in HashMap?

We know that two objects are considered equal only if their references point to the same object, and unless we override equals and hashCode methods, the class object will not behave properly on hash-based collections like HashMap , HashSet , and Hashtable .


2 Answers

Since the HashMap has the exact object that you're looking for, it doesn't need to call equals to verify that the object is the right one.

When you get an object from a HashMap, first the hashCode is evaluated to find the right bucket. Then, the bucket is searched. But each key in the bucket is compared first using ==. If the object is not the one that is being sought, then equals is used.

In Java 7, the key part of the code, in the get method of HashMap is

if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
    return e.value;
like image 146
Dawood ibn Kareem Avatar answered Sep 28 '22 01:09

Dawood ibn Kareem


This question has been asked before in here.

According to the hashCode method, it states "If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result." In general, whenever you create your equals method, make sure it is consistent to the returning hashcode value.

The HashMap will always compare the objects using the hashCode before the equal method. For your case if you would like to see the equal method to be invoked, you can simulate the hash collision scenario by just making the hashcode value to be a constant. (Caveat: This is not a bad example as it impacts a lot in term of performance.)

/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    Map<Object, String> m = new HashMap<Object, String>();
    Dog d1 = new Dog("clover");
    Dog d2 = new Dog("clover 2");
    m.put(d1, "Dog 1");
    m.put(d2, "Dog 2");
    System.out.println(m.get(d1)); 
}

class Dog {
private String name;
public Dog(String n) {   
    name = n; 
}

@Override
public boolean equals(final Object o) {
    System.out.println("equals called..");
    return true;
}

@Override
public int hashCode() {
    System.out.println("hashCodecalled..");
    return 1; // constant
}}

and the result:

hashCodecalled..

hashCodecalled..

equals called..

hashCodecalled..

Dog 2

And finally of course you need to insert at least two object to make it works.

like image 43
bLaXjack Avatar answered Sep 27 '22 23:09

bLaXjack