Overriding a method which has a parameter of the abstract base class

Raphael Tarita :

So, the problem is: I have an abstract base class (Property) which has an abstract member method (same()). The same() method returns boolean and should check for equality, but "equality" may be interpreted differently in the subclasses, therefore I am not overriding equals() or compareTo(). Because it tests for equality with another object of its type, the signature looks like that:

public abstract boolean same(Property other);

Now, when I am trying to override it in class, let's say "SubProperty", i cannot use SubProperty as the type of the parameter. I know about the reasons of this in general and the recommendation to add type bounds, but things are getting more complicated because the parameter type is its own class.

Is there any smooth way to override the method properly?

Because it was recommended in other StackOverflow questions, I tried to use type bounds (which are in this case circular). So, the class would look like this:

public abstract class Property<T extends Property<T>>

and the same() method:

public abstract boolean same(T other);

For the subclass this means:

public class SubProperty extends Property<SubProperty>

and the same()method:

public boolean same(SubProperty other);

This would be the result if I would use type bounds as recommended. It actually builds, but I don't even know if it would work properly. Anyway, it looks horrible and unmaintainable (especially because I am using 2 other generic type arguments in Property).

I hope that there is some other way to do this. If it matters, I am using java 1.8 (openjdk 1.8.0.212-b04)

EDIT 1:

Because people asked: same() is not anything like equals() or compareTo(). Yes, it is about equality in some sense. But actually I think it is easier to describe it like this:

same() is a method that checks for something in this and some other object of the same class and returns true or false according to what happened in the method.

EDIT 2:

As @davidxxx explained, it seems to be impossible to make the code any "smoother". I will probably just leave the base class parameter and check which object I got inside the method. Seems not too bad after all.

davidxxx :

Unfortunately you don't have other ways because in Java the return type is covariant but the parameter type is not because it would be contrary to the liskov principle.

Liskov's notion of a behavioural subtype defines a notion of substitutability for objects; that is, if S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program (e.g. correctness).

Here is a simple example that shows why this rule matters.

Suppose the subclass :

public class FooProperty extends Property{
    public boolean same(FooProperty other){...}
}

Suppose that you instantiate it in this way :

Property property = new FooProperty();

You can so do :

property.same(new FooProperty());

But you can also do :

property.same(new Property());

But that is not consistent in terms of expected parameter for the FooProperty.same() override that expects a FooProperty.
And that violates the liskov principle because I should be able to replace any Property instance by any subclass of that.


Only, the generic type declared on the class as in your example allows to bypass this limitation and to leave the subclass makes its mind about the subclass to use as parameter.

Anyway, it looks horrible and unmaintainable

That is very maintainable since if you refactor the class name, it will be updated. But that is a little verbose indeed.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=165944&siteId=1