mattlove
mattlove

Reputation: 25

Does the compiler, or JVM, enforce the hashCode/equals contract?

The object I'm storing in the HashMap as the key overrides equals() but not hashCode(); When I put an object in the map, the equals() method is not being invoked. If I also override hashCode(), the equals() method is invoked. Why is that?

Why am I unable to utilize a custom equals method, to possibly prevent the addition of an object to a map, regardless of whether I override hashCode()?

Thanks.

package package1;

public class PlayWithHash {

    public static void main(String [] args){
        java.util.Map<Cat, Cat> map = new java.util.HashMap<Cat, Cat>();
        map.put(new Cat(), new Cat());
        map.put(new Cat(), new Cat());
        System.out.println("hashmap size = " + map.size());
    }
}

class Cat{
    @Override
    public int hashCode(){
        return 1;
    }
    @Override
    public boolean equals(Object d){
        Cat c = (Cat) d;
        if(this.hashCode() == c.hashCode()){
            return true;
        }
        return false;
    }
}

If hashCode() is commented, size = 2, otherwise size = 1.

I’m thinking that if I don’t override hashCode() and Object’s hashCode() is used instead, HashMap will “see” that the hashCodes are different for my two objects and come to the conclusion there is no need to invoke equals(). If that’s true, HashMap is enforcing, at least part of, the contract. And, this could be another manifestation of HashMap optimization.

But, you (greenSocksRock) wrote, “…the hashCode() implementation of your key is not returning sufficiently different hash values for different keys.” Would you elaborate please?

Thanks.

PS Sorry that I'm still trying to figure out my way around StackOverflow's editor.

Upvotes: 0

Views: 651

Answers (3)

neeraj baji
neeraj baji

Reputation: 211

A hashmap is internally implemented as a collection of linked lists. The usual mechanism to search for an object(with the passed key) is to first hash the key and then go through individual objects in the linked list corresponding to the hashed value.

By the same logic, for objects inside a HashMap the equals() method would only be invoked once the hashCode() method returns the same hash value for two objects.

Hence, it is always advisable to override not only the equals() method but the hashCode() method as well when implementing custom classes.

Upvotes: 0

fspinnenhirn
fspinnenhirn

Reputation: 1889

Neither the compiler, nor the JVM enforces the hashCode/equals contract. The contract is between Object and your class, i.e. you're responsible to obey and enforce that contract!

In Java, the Object class lays out the contract for .equals() and .hashCode(), which most hash-based standard library classes rely on. Now if you implement your own class, it implicitly extends Object, and thus you should be enforcing the general contract within your own implementation, if you want your class to work correctly with those other classes that rely on that contract.

As a reminder, from the Object documentation:

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.

Without seeing your implementation, I can only guess as to why equals() is being invoked when you put your object in a Map, and my guess would be that the hashCode() implementation of your key is not returning sufficiently different hash values for different keys.
When you put something into a HashMap, for instance, it will call the key's hashCode() method, to find a spot to store your value. If that spot already contains a value, the key's equals() method might get called to figure out what to do next.

I'm not sure if I understand what you're trying to do in your last question, when you say you want to "prevent the addition of an object to a map". That is something you would definitely be able to do with a custom equals implementation, if you wanted to. Take a look at Map.containsKey() or Map.containsValue(), depending on your situation, prior to putting a new entry into the map.

Finally, I'd recommend looking at Items 8 and 9 in Joshua Bloch's "Effective Java, 2nd ed." for a more in-depth explanation, if you can.

Upvotes: 3

Yogesh_D
Yogesh_D

Reputation: 18764

AFAIK the complier doesnt enforce it. Read this for a better understanding of the topic http://tutorials.jenkov.com/java-collections/hashcode-equals.html

Upvotes: 0

Related Questions