Why do I need to override the equals and hashCode

2018-12-30 23:27发布

Recently I read through this Developer Works Document.

The document is all about defining hashCode() and equals() effectively and correctly, however I am not able to figure out why we need to override these two methods.

How can I take the decision to implement these methods efficiently?

29条回答
春风洒进眼中
2楼-- · 2018-12-31 00:15

1) The common mistake is shown in the example below.

public class Car {

    private String color;

    public Car(String color) {
        this.color = color;
    }

    public boolean equals(Object obj) {
        if(obj==null) return false;
        if (!(obj instanceof Car))
            return false;   
        if (obj == this)
            return true;
        return this.color.equals(((Car) obj).color);
    }

    public static void main(String[] args) {
        Car a1 = new Car("green");
        Car a2 = new Car("red");

        //hashMap stores Car type and its quantity
        HashMap<Car, Integer> m = new HashMap<Car, Integer>();
        m.put(a1, 10);
        m.put(a2, 20);
        System.out.println(m.get(new Car("green")));
    }
}

the green Car is not found

2. Problem caused by hashCode()

The problem is caused by the un-overridden method hashCode(). The contract between equals() and hashCode() is:

  1. If two objects are equal, then they must have the same hash code.
  2. If two objects have the same hash code, they may or may not be equal.

    public int hashCode(){  
      return this.color.hashCode(); 
    }
    
查看更多
几人难应
3楼-- · 2018-12-31 00:15

String class and wrapper classes have different implementation of equals() and hashCode() methods than Object class. equals() method of Object class compares the references of the objects, not the contents. hashCode() method of Object class returns distinct hashcode for every single object whether the contents are same.

It leads problem when you use Map collection and the key is of Persistent type, StringBuffer/builder type. Since they don't override equals() and hashCode() unlike String class, equals() will return false when you compare two different objects even though both have same contents. It will make the hashMap storing same content keys. Storing same content keys means it is violating the rule of Map because Map doesnt allow duplicate keys at all. Therefore you override equals() as well as hashCode() methods in your class and provide the implementation(IDE can generate these methods) so that they work same as String's equals() and hashCode() and prevent same content keys.

You have to override hashCode() method along with equals() because equals() work according hashcode.

Moreover overriding hashCode() method along with equals() helps to intact the equals()-hashCode() contract: "If two objects are equal, then they must have the same hash code."

When do you need to write custom implementation for hashCode()?

As we know that internal working of HashMap is on principle of Hashing. There are certain buckets where entrysets get stored. You customize the hashCode() implementation according your requirement so that same category objects can be stored into same index. when you store the values into Map collection using put(k,v)method, the internal implementation of put() is:

put(k, v){
hash(k);
index=hash & (n-1);
}

Means, it generates index and the index is generated based on the hashcode of particular key object. So make this method generate hashcode according your requirement because same hashcode entrysets will be stored into same bucket or index.

That's it!

查看更多
其实,你不懂
4楼-- · 2018-12-31 00:15

Both the methods are defined in Object class. And both are in its simplest implementation. So when you need you want add some more implementation to these methods then you have override in your class.

For Ex: equals() method in object only checks its equality on the reference. So if you need compare its state as well then you can override that as it is done in String class.

查看更多
忆尘夕之涩
5楼-- · 2018-12-31 00:16

Identity is not equality.

  • equals operator == test identity.
  • equals(Object obj) method compares equality test(i.e. we need to tell equality by overriding the method)

Why do I need to override the equals and hashCode methods in Java?

First we have to understand the use of equals method.

In order to identity differences between two objects we need to override equals method.

For example:

Customer customer1=new Customer("peter");
Customer customer2=customer1;
customer1.equals(customer2); // returns true by JVM. i.e. both are refering same Object
------------------------------
Customer customer1=new Customer("peter");
Customer customer2=new Customer("peter");
customer1.equals(customer2); //return false by JVM i.e. we have two different peter customers.

------------------------------
Now I have overriden Customer class equals method as follows:
 @Override
    public boolean equals(Object obj) {
        if (this == obj)   // it checks references
            return true;
        if (obj == null) // checks null
            return false;
        if (getClass() != obj.getClass()) // both object are instances of same class or not
            return false;
        Customer other = (Customer) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name)) // it again using bulit in String object equals to identify the difference 
            return false;
        return true; 
    }
Customer customer1=new Customer("peter");
Customer customer2=new Customer("peter");
Insteady identify the Object equality by JVM, we can do it by overring equals method.
customer1.equals(customer2);  // returns true by our own logic

Now hashCode method can understand easily.

hashCode produces integer in order to store object in data structures like HashMap, HashSet.

Assume we have override equals method of Customer as above,

customer1.equals(customer2);  // returns true by our own logic

While working with data structure when we store object in buckets(bucket is a fancy name for folder). If we use built-in hash technique, for above two customers it generates two different hashcode. So we are storing the same identical object in two different places. To avoid this kind of issues we should override the hashCode method also based on the following principles.

  • un-equal instances may have same hashcode.
  • equal instances should return same hashcode.
查看更多
牵手、夕阳
6楼-- · 2018-12-31 00:16
class A {
    int i;
    // Hashing Algorithm
    if even number return 0 else return 1
    // Equals Algorithm,
    if i = this.i return true else false
}
  • put('key','value') will calculate the hash value using hashCode() to determine the bucket and uses equals() method to find whether the value is already present in the Bucket. If not it will added else it will be replaced with current value
  • get('key') will use hashCode() to find the Entry (bucket) first and equals() to find the value in Entry

if Both are overridden,

Map<A>

Map.Entry 1 --> 1,3,5,...
Map.Entry 2 --> 2,4,6,...

if equals is not overridden

Map<A>

Map.Entry 1 --> 1,3,5,...,1,3,5,... // Duplicate values as equals not overridden
Map.Entry 2 --> 2,4,6,...,2,4,..

If hashCode is not overridden

Map<A>

Map.Entry 1 --> 1
Map.Entry 2 --> 2
Map.Entry 3 --> 3
Map.Entry 4 --> 1
Map.Entry 5 --> 2
Map.Entry 6 --> 3 // Same values are Stored in different hasCodes violates Contract 1
So on...

HashCode Equal Contract

  1. Two keys equal according to equal method should generate same hashCode
  2. Two Keys generating same hashCode need not be equal (In above example all even numbers generate same hash Code)
查看更多
时光乱了年华
7楼-- · 2018-12-31 00:16

IMHO, it's as per the rule says - If two objects are equal then they should have same hash, i.e., equal objects should produce equal hash values.

Given above, default equals() in Object is == which does comparison on the address, hashCode() returns the address in integer(hash on actual address) which is again distinct for distinct Object.

If you need to use the custom Objects in the Hash based collections, you need to override both equals() and hashCode(), example If I want to maintain the HashSet of the Employee Objects, if I don't use stronger hashCode and equals I may endup overriding the two different Employee Objects, this happen when I use the age as the hashCode(), however I should be using the unique value which can be the Employee ID.

查看更多
登录 后发表回答