Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What will go wrong when superclass does not redeclare equals() and hashCode()?

Tags:

java

Suppose there are two classes like this:

abstract class A { /* some irrelevant methods */ }  class B extends A {     public final int x;      public B(final int x) {         this.x = x;     }      /* some more irrelevant methods */ } 

Then I generate the equals() and hashCode() methods on class B using Eclipse's "Source → Generate hashCode() and equals()...". But Eclipse warns me that:

The super class 'com.example.test2.A' does not redeclare equals() and hashCode() - the resulting code may not work correctly.

So, what will make the resulting code not working correctly with the generated methods?


(BTW, the generated methods look like this:

@Override public int hashCode() {     final int prime = 31;     int result = 1;     result = prime * result + x;     return result; }  @Override public boolean equals(Object obj) {     if (this == obj)         return true;     if (obj == null)         return false;     if (getClass() != obj.getClass())         return false;     B other = (B) obj;     if (x != other.x)         return false;     return true; } 

)

like image 786
kennytm Avatar asked Apr 26 '13 12:04

kennytm


People also ask

What is the importance of the hashCode () and equals () contract?

The general contract of hashCode is: During the execution of the application, if hashCode() is invoked more than once on the same Object then it must consistently return the same Integer value, provided no information used in equals(Object) comparison on the Object is modified.

What is role of equals () and hashCode () method in object class?

Uses of hashCode() and equals() Methods By default, two objects are equal if and only if they are refer to the same memory location. Most Java classes override this method to provide their own comparison logic. hashcode() – returns a unique integer value for the object in runtime.

Why is it important to override hashCode () when you override equals () in Java?

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.

Can we override a equals () and hashCode () method How?

if you override equals, you must override hashCode. hashCode must generate equal values for equal objects. equals and hashCode must depend on the same set of significant fields . You must use the same set of fields in both of these methods.


1 Answers

You must be careful when overriding equals to adhere to a specific set of rules. See the javadoc for details. In short, two tricky parts are preserving symmetry and transitivity. According to Joshua Block's Effective Java

"There is no way to extend an instantiable class and add a value component while preserving the equals contract"

What does this mean? Well let's say you have in class A a property of type T and in subclass B another property of type V. If both classes override equals then you'll get different results when comparing A to B than B to A.

A a = new A(T obj1); B b = new B(T obj1, V obj2); a.equals(b) //will return true, because objects a and b have the same T reference. b.equals(a) //will return false because a is not an instanceof B 

This is a violation of symmetry. If you try and correct this by doing mixed comparisions, you'll lose transitivity.

B b2 = new B(T obj1, V obj3); b.equals(a) // will return true now, because we altered equals to do mixed comparisions b2.equals(a) // will return true for the same reason b.equals(b2) // will return false, because obj2 != obj3 

In this case b == a, b2 ==a, b != b2, which is a problem.

EDIT

In an effort to more precisely answer the question: "what will make the resulting code not working correctly with the generated methods" let's consider this specific case. The parent class is abstract and does not override equals. I believe we can conclude that the code is safe and no violation of the equals contract has occurred. This is a result of the parent class being abstract. It cannot be instantiated, therefore the above examples do not apply to it.

Now consider the case when the parent class is concrete and does not override equals. As Duncan Jones pointed out, the warning message is still generated, and in this case seems correct to do so. By default, all classes inherit equals from Object, and will be compared based on object identify (i.e. memory address). This could result in a unsymmetrical comparison if used with a subclass that does override equals.

A a = new A(); B b = new B(T obj1); a.equals(b) //will return false, because the references do not point at the same object b.equals(a) //should return false, but could return true based on implementation logic.  

If b.equals(a) returns true for whatever reason, either implementation logic or programming error, a loss of symmetry will result. The compiler has no way to enforce this, hence, a warning is generated.

like image 141
Mike Avatar answered Oct 17 '22 00:10

Mike