Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make overriding method return a different type

Suppose I have the following classes:

public class Test { 

    public static void main(String[] args) {
        PetrolCar myCar = new PetrolCar();
        String mileage = myCar.getEngine().getMileage();

    }
}

class Engine {
    protected String var = "Engine";

    protected String getVar() {
        return this.var;
    }
}

class PetrolEngine extends Engine {
    protected String var = "PetrolEngine";
    protected String mileage = "0";

    PetrolEngine() {
        super();
        mileage = "100";
    }

    protected String getVar() {
        return this.var;
    }

    protected String getMileage() {
        return mileage;
    }
}

class Car {
    protected Engine engine;

    protected Engine getEngine() {
        return engine;
    }
}

class PetrolCar extends Car {
    protected PetrolEngine engine;
}

Obviously myCar.getEngine().getMileage() will not work because getEngine() will return an Engine instance, not a PetrolEngine instance. What is the workaround for this? I don't want to redefine getEngine() in all subtypes of Car, at the same time I would like to get back the more specific type PetrolEngine when I call getEngine() on an instance of PetrolCar, without having to type cast. Is this possible?

In other words, is there a way I can associate the Engine of PetrolCar to be a PetrolEngine? In the above case, it is creating two separate instance variables engine, one of PetrolEngine type inside PetrolCar, and another Engine, which I can access as super.getEngine() from inside PetrolCar. I don't want different variables. What I would like is that the code should know that the "Engine" of "PetrolCar" is a PetrolEngine.

EDIT: Changed MyCar to PetrolCar to avoid confusion which is leading everyone to believe that MyCar should be an instance of Car rather than a subtype.

like image 421
Hari Menon Avatar asked May 23 '26 23:05

Hari Menon


1 Answers

Yes you can. They call it covariant return (starting from Java 1.5):

public class Test {

    public static void main(String[] args) {

        MyCar car = ...;
        car.getEngine().getMileage();
    }
}

interface Car {
    Engine getEngine();
}

interface MyCar extends Car {
    PetrolEngine getEngine();
}

interface Engine {
}

interface PetrolEngine extends Engine {
    String getMileage();
}