Austin
Austin

Reputation: 1255

Passing derived class object which expects a base class object

public abstract class AbstractClass 
{
    public abstract void AbstractClassMethod();
}


public class DerivedClass extends AbstractClass {

    @Override
    public void AbstractClassMethod() {
        // TODO Auto-generated method stub

    }

}



public interface InterfaceObject 
{
    public void InterfaceObjectMethod(AbstractClass oAbstractClass);
}



public class TestAbstractParam implements InterfaceObject {

    @Override
    public void InterfaceObjectMethod(AbstractClass oAbstractClass) {
        // TODO Auto-generated method stub

    }

}



public class TestDerivedParam implements InterfaceObject {

    @Override
    public void InterfaceObjectMethod(DerivedClass oDerivedClass) {
        // TODO Auto-generated method stub

    }

}

I am getting error while compiling TestDerivedParam class. Can anyone please explain the reason behind this? More specifically, the question is why a method cant accept a child type parameter which is expecting a base type? Thank you!

Upvotes: 0

Views: 2317

Answers (2)

Bhesh Gurung
Bhesh Gurung

Reputation: 51030

In TestDerivedParam the method

public void InterfaceObjectMethod(DerivedClass oDerivedClass) {

is not same as

public void InterfaceObjectMethod(AbstractClass oAbstractClass);

in InterfaceObject.

You are using @Override annotation but are not using the same method signature.


More specifically, the question is why a method cant accept a child type parameter which is expecting a base type?

See the example below:

public class Fruit { }

public class Apple extends Fruit { }

public class Banana extends Fruit { }

Both Apple and Banana are Fruit but Apple is not Banana and Banana is not Apple. So, you can't really give Banana to somebody who is expecting Apple, but it would be valid to give either a Banana or an Apple to somebody who is just expecting a Fruit.

So,

public void method(Fruit fruit) {

does not have same signature as

public void method(Apple apple) {

because, if it was then that would mean the following has the same signature as the above

public void method(Banana banana) {

And the signature has to match while overriding (implementing) a method.

Upvotes: 1

Edwin Dalorzo
Edwin Dalorzo

Reputation: 78579

You are changing the signature of the method, as such, Java can only assume your intention is to "overload" an existing method with the same name and different parameters.

You may alternatively use a bridge method:

@Override
public void InterfaceObjectMethod(AbstractClass oDerivedClass) {
   // TODO Auto-generated method stub
}

public void InterfaceObjectMethod(DerivedClass oDerivedClass) {
   InterfaceObjectMethod((AbstractClass)oDerivedClass);
}

This second method would be a bridge method, whose responsibility is simply forwarding your request to the actual inherited method. As you can see the bridge method is an overloading, not an overriding.

Another option is to use generics.

interface InterfaceObject<T extends AbstractClass> 
{
    public void InterfaceObjectMethod(T oAbstractClass);
}


class TestAbstractParam implements InterfaceObject<AbstractClass> {

    @Override
    public void InterfaceObjectMethod(AbstractClass oAbstractClass) {
        // TODO Auto-generated method stub

    }
}

class TestDerivedParam implements InterfaceObject<DerivedClass> {

    @Override
    public void InterfaceObjectMethod(DerivedClass oDerivedClass) {
        // TODO Auto-generated method stub

    }
}

Ultimately, the generics version does exactly the same as the first option, that is, a bridge method is synthetically generated by the compiler. If you decompile your classes you would notice it does exactly that.

Upvotes: 0

Related Questions