Search code examples
javainheritanceoverridingabstract-class

Override class of parameter in method if it extends that of parameter used in abstract method


Suppose I have the following four classess, out of which two are abstract and two are concrete: Abstract1, Concrete1, Abstract2, Concrete2.

Concrete1 extends Abstract1 and Concrete2 extends Abstract2.

Suppose I have the following four classess, out of which two are abstract and two are concrete: AbstractProp, ConcreteProp, AbstractClass, ConcreteClass.

ConcreteProp extends AbstractProp and ConcreteClass extends AbstractClass.

The code for AbstractClass would look like the following:

public abstract class AbstractClass {
    protected AbstractProp someProperty;

    public abstract void setProperty(AbstractProp someProperty);
}

When implementing ConcreteClass, I want to be able to do something like this (keep in mind that AbstractProp extends `ConcreteProp):

public class ConcreteClass extends AbstractClass {
    @Override
    public void setProperty(ConcreteProp someProperty) {
        this.someProperty = someProperty;
    }
}

But this last bit of code isn't valid because the classes of the parameters (AbstractProp and ConcreteProp) in setProperty() differ, making the @Override annotation invalid. Is there a way I can accomplish what I'm trying to do here, perhaps using generics and/or wildcards?

NOTE: I'm aware that this type of naming is bad practice and the code is oversimplistic, I'm not actually using it and this is just an example to keep the question as simple as possible.


Solution

  • If you introduce generics on the AbstractClass you can achieve what you are requesting.

    public abstract class AbstractClass<T extends AbstractProp> {
        protected T someProperty;
    
        public void setProperty(T someProperty) {
            this.someProperty = someProperty;
        }
    }
    

    And then specify that you want ConcreteProp to be the type you want in your ConcreteClass.

    public class ConcreteClass extends AbstractClass<ConcreteProp> {
    
        @Override
        public void setProperty(final ConcreteProp someProperty) {
            this.someProperty = someProperty;
        }
    }