Why to use Polymorphism?

The reason why you use polymorphism is when you build generic frameworks that take a whole bunch of different objects with the same interface. When you create a new type of object, you don't need to change the framework to accommodate the new object type, as long as it follows the "rules" of the object.

So in your case, a more useful example is creating an object type "Airport" that accepts different types of FlyingMachines. The Airport will define a "AllowPlaneToLand" function, similar to:

//pseudocode
void AllowPlaneToLand(FlyingMachine fm)
{
    fm.LandPlane();
}

As long as each type of FlyingMachine defines a proper LandPlane method, it can land itself properly. The Airport doesn't need to know anything about the FlyingMachine, except that to land the plane, it needs to invoke LandPlane on the FlyingMachine. So the Airport no longer needs to change, and can continue to accept new types of FlyingMachines, be it a handglider, a UFO, a parachute, etc.

So polymorphism is useful for the frameworks that are built around these objects, that can generically access these methods without having to change.


What is the advantage of polymorphism when both flm.fly() and j.fly() give me the same answer?

The advantage is that

FlyingMachines flm = new Jet();
flm.fly();

returns

"Start, Taxi, Fly"

instead of

"No implementation"

That's polymorphism. You call fly() on an object of type FlyingMachine and it still knows that it is in fact a Jet and calls the appropriate fly() method instead of the wrong one which outputs "No implementation".

That means you can write methods that work with objects of type FlyingMachine and feed it with all kinds of subtypes like Jet or Helicopter and those methods will always do the right thing, i.e. calling the fly() method of the appropriate type instead of always doing the same thing, i.e. outputting "No implementation".

Polymorphism

Polymorphism is not useful in your example.

  • a) It gets useful when you have different types of objects and can write classes that can work with all those different types because they all adhere to the same API.

  • b) It also gets useful when you can add new FlyingMachines to your application without changing any of the existing logic.

a) and b) are two sides of the same coin.

Let me show how.

Code example

import java.util.ArrayList;
import java.util.List;

import static java.lang.System.out;

public class PolymorphismDemo {

    public static void main(String[] args) {
        List<FlyingMachine> machines = new ArrayList<FlyingMachine>();
        machines.add(new FlyingMachine());
        machines.add(new Jet());
        machines.add(new Helicopter());
        machines.add(new Jet());

        new MakeThingsFly().letTheMachinesFly(machines);
    }
}

class MakeThingsFly {
    public void letTheMachinesFly(List<FlyingMachine> flyingMachines) {
        for (FlyingMachine flyingMachine : flyingMachines) {
            flyingMachine.fly();
        }
    }
}

class FlyingMachine {
    public void fly() {
        out.println("No implementation");
    }
}

class Jet extends FlyingMachine {
    @Override
    public void fly() {
        out.println("Start, taxi, fly");
    }

    public void bombardment() {
        out.println("Fire missile");
    }
}

class Helicopter extends FlyingMachine {
    @Override
    public void fly() {
        out.println("Start vertically, hover, fly");
    }
}

Explanation

a) The MakeThingsFly class can work with everything that is of type FlyingMachine.

b) The method letTheMachinesFly also works without any change (!) when you add a new class, for example PropellerPlane:

public void letTheMachinesFly(List<FlyingMachine> flyingMachines) {
        for (FlyingMachine flyingMachine : flyingMachines) {
            flyingMachine.fly();
        }
    }
}

That's the power of polymorphism. You can implement the open-closed-principle with it.


In your example, the use of polymorphism isn't incredibly helpful since you only have one subclass of FlyingMachine. Polymorphism becomes helpful if you have multiple kinds of FlyingMachine. Then you could have a method that accepts any kind of FlyingMachine and uses its fly() method. An example might be testMaxAltitude(FlyingMachine).

Another feature that is only available with polymorphism is the ability to have a List<FlyingMachine> and use it to store Jet, Kite, or VerySmallPebbles.

One of the best cases one can make for using polymorphism is the ability to refer to interfaces rather than implementations.

For example, it's better to have a method that returns as List<FlyingMachine> rather than an ArrayList<FlyingMachine>. That way, I can change my implementation within the method to a LinkedList or a Stack without breaking any code that uses my method.