简体   繁体   中英

Method overloading using derived types as parameters in Java

Let's say I have existing code which I want to extend but also to avoid changing it as much as possible.

Somewhere around this code there is a method that receives some type.

Engine.method(Base b) 

Now, I want to extend this functionality. So I extends Base into a type called Derived which holds some more data I need and I also implements another method that receives the Derived type and do something different with it.

Engine.method(Derived d)

But I don't want to change the original call to "method". I somehow managed to instansiate the correct type (Base or Derived) by using a flag but since the original call is taking the Base then my new method will not be called.

Base b = null;
if(flag) {
   b = new Derived()
} else{
   b = new Base()
} 
Engine.method(b) 

The problem is that now my Engine.method(Derived d) will not be called. I worked-around it by using casting

if(flag)
Engine.method((Derived)b) 

But that's wrong and stupid. Any suggestions?

I can always do:

if(flag) {
   Engine.methodForBase(new Base())
} else{
   Engine.methodForDerived(new Derived())
} 

But can you think of something better?

Thanks

That happens because Java uses single dispatch. This ends meaning that in your case, the method called depends on the type of reference "b", which is Base, and not on the type of the instance that "b" holds. Therefore, method xpto.(Base b) will always be called.

You really have to cast it or use the last approach you wrote.

Write this:

class Engine {
    public static void method(Base argument) {
        if (argument instanceof Derived) {
            // ...
        }
        else {
            // ...
        }
    }
}

But probably, you should extend your Engine class to allow for more polymorphism, eg do something like this:

interface Engine<T extends Base> {
    void method(T argument);
}

And have implementations for Base and Derived like this:

class BaseEngine implements Engine<Base> {
    @Override
    public void method(Base argument) { ... }
}

class DerivedEngine implements Engine<Derived> {
    @Override
    public void method(Derived argument) { ... }
}

Why not simply call the method with a parameter of the correct type?

Base b = null;
if (flag) {
    Derived d = new Derived()
    Engine.method(d); // so the correct method will be used for Derived
    b = d;
} else{
    b = new Base()
    Engine.method(b) 
}

You could also consider reusing the method(Base b) :

public void method(Derived d) {
    method((Base)b);
    ...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM