19

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.

Eran
  • 387,369
  • 54
  • 702
  • 768
gontard
  • 28,720
  • 11
  • 94
  • 117
  • 1
    It's the opposite here - the base class has an abstract method and a non-abstract derived class has a non-abstract method which overrides the base class method. – sharptooth Jun 17 '15 at 08:38
  • 1
    @sharptooth My question was not very clear. I am talking about `A::equals` overriding `Object::equals` – gontard Jun 17 '15 at 08:43
  • I guess you should word that explicitly in the question. Since you only presented two of your classes I was sure the question was about them only. – sharptooth Jun 17 '15 at 08:54
  • @sharptooth i have edited my question – gontard Jun 17 '15 at 12:17
  • `A` is not overriding `B`'s `equals()`, it's `B` overriding `A`, and is one of the most common thing to do when designing classes, because it forces you to do the implementation in `B` of `equals()`, it's like an `interface` – JorgeeFG Jun 17 '15 at 15:54

5 Answers5

24

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()).

Eran
  • 387,369
  • 54
  • 702
  • 768
  • If `B` has no other properties (and neither has `A`) which make instances different from each other, an implementation like in the question might be sensible. Though comparing with `this.getClass()` instance of `B.class` would be more correct when considering subclasses of `B`. – Paŭlo Ebermann Jun 17 '15 at 19:03
  • Yeah, maybe `B` is a Singleton – aebabis Jun 17 '15 at 20:05
10

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.

npinti
  • 51,780
  • 5
  • 72
  • 96
  • You are clear-sighted, i really saw this *as removing functionality*. – gontard Jun 17 '15 at 07:47
  • @gontard: In this case, you *want* implementing classes to stipulate their own behaviour. To do this, you would need to ensure that the default implementation is not accessible so that the desired behaviour is obtained. – npinti Jun 17 '15 at 07:49
  • Actually it [is still accessable](http://stackoverflow.com/a/2692379/823393) but not at all easily. – OldCurmudgeon Jun 17 '15 at 08:58
  • @OldCurmudgeon: I would hope that no one would do something like that by accident XD – npinti Jun 17 '15 at 09:34
6

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.

Kevin Krumwiede
  • 9,868
  • 4
  • 34
  • 82
3

It means you must implement your own equals() method

1

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.

Community
  • 1
  • 1
cosbor11
  • 14,709
  • 10
  • 54
  • 69