Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java - equals method in base class and in subclasses

Tags:

I have a simple base class, which is later extended by many separate classes, which potentially introduce new fields, but not necessarily. I defined an equals method in the base class, but also overriden that for a few subclasses. Is it OK to mix definitions in base/subclasses? In my case it was to avoid code duplication checking the same fields.

like image 975
Bober02 Avatar asked Oct 31 '12 16:10

Bober02


People also ask

What is the difference between equals () method and ==?

In simple words, == checks if both objects point to the same memory location whereas . equals() evaluates to the comparison of values in the objects.

Do all Java classes have an equals method?

The equals method is defined in Object and since all classes inherit from it, all have that method. The implementation in Object checks identity (note that identical variables are equal as well), but many classes override it with something more suitable.

Which reference types inherit the equals method?

The equals method that is inherited from the Object class only returns true if the two objects references refer to the same object.

Why use .equals instead of == Java?

The == operator can't compare conflicting objects, so at that time the compiler surrenders the compile-time error. The equals() method can compare conflicting objects utilizing the equals() method and returns “false”.


1 Answers

Take a look at "Implementing equals() To Allow Mixed-Type Comparison" from Angelika Langer .

Here is a brief explanation of some problems and a possible solution:

The equals contract says (amongst others):

It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.

That means you might get problems if your sub class is introducing new fields and you're comparing an object of the base class (or another sub class that doesn't override equals) to an object of this sub class.

Do NOT do the following:

class BaseClass {     private int field1 = 0;      @Override     public boolean equals(Object obj) {         if (obj instanceof BaseClass) {             return field1 == ((BaseClass) obj).field1;         }         return false;     } }  class BadSubClass extends BaseClass {     private int field2 = 0;      @Override     public boolean equals(Object obj) {         if (obj instanceof BadSubClass) {             return super.equals(obj)                      && field2 == ((BadSubClass) obj).field2;         }         return false;     } } 

because you get

BaseClass baseClass = new BaseClass(); BadSubClass subClass = new BadSubClass();  System.out.println(baseClass.equals(subClass)); // prints 'true' System.out.println(subClass.equals(baseClass)); // prints 'false' 

A possible solution:

Replace the instanceof-check with a class comparison:

obj != null && obj.getClass() == getClass() 

With this solution an object of BaseClass will never be equal to an object of any subclass.

If you create another SubClass without an @Override of the equals method, two SubClass-objects can be equal to each other (if the BaseClass.equals check decides so) out of the box, but a SubClass-object will never be equal to a BaseClass-object.

A good implementation could be as follows:

class BaseClass {     private int field1 = 0;      @Override     public boolean equals(Object obj) {         if (obj != null && obj.getClass() == getClass()) {             return field1 == ((BaseClass) obj).field1;         }         return false;     } }  class GoodSubClass extends BaseClass {     private int field2 = 0;      @Override     public boolean equals(Object obj) {         if (obj instanceof GoodSubClass) {             return super.equals(obj) && field2 == ((GoodSubClass) obj).field2;         }         return false;     } } 

Please refer to the article mentioned above for more advanced problems and their solutions.

like image 177
Raph Avatar answered Oct 13 '22 11:10

Raph