I use a library where an abstract class overrides a concrete method inherited from Object
with an abstract method:
public abstract class A {
@Override
public abstract boolean equals(Object obj);
}
To extend this class, I have to implement the equals
method:
public class B extends A {
@Override
public boolean equals(Object obj) {
return obj != null && obj.getClass() == B.class;
}
}
Why can an abstract method (A::equals
) override a concrete method (Object::equals
)? I don't see the goal of this.
In this specific example it makes perfect sense. If sub-classes of A are meant to be used in Collections, where equals
is widely used to locate objects, making A
's equals
method abstract forces you to give non-default implementation of equals
in any sub-classes of A
(instead of using the default implementation of the Object class which only compares instance references).
Of course, your suggested implementation of equals
in B makes little sense. You should be comparing the properties of the 2 B instances to determine if they are equal.
This is a more suitable implementation :
public class B extends A {
@Override
public boolean equals(Object obj) {
if (!(obj instanceof B))
return false;
B other = (B) obj;
return this.someProperty.equals(other.someProperty) && this.secondProperty.equals(other.secondProperty);
}
}
In addition, remember to override hashCode
whenever you override equals
(since the contract of equals
and hashCode
requires that if a.equals(b) == true
then a.hashCode() == b.hashCode()
).
Because in this case, you would want your objects to define their own equals
, which supposedly will behave differently from the default implementation.
You should not look at this as removing functionality, but rather as enforcing that inheriting objects implement their own.
This would allow you to force a subclass to reimplement a method. Whether this is a good idea or not is another matter. You would only do this if you wanted to enforce a stronger contract than the original method provided. You should then carefully document the new contract.
It means you must implement your own equals()
method
Because all classes in Java inherently extend the Object class. Class A
will inherit the Object#equals
method. Suppose you wanted to force a compile error when the equals method is not explicitly implemented like in this example. Making the equals method abstract without an implementation block would enable you to do this.