Polymorphism doesn't work in method arguments in Java

The problem here is that Java does not support dynamic binding of method arguments. What you see is static binding, i.e. the overload of the method to call is chosen at compile time.

See also: Static Binding and Dynamic Binding


Method overloading type polymorphism is determined at the compile time in Java.

Meaning that Java has to infer type of the method parameters from the reference type they represent, as it has no idea about the type of object they hold at the compile time.

We can argue that it's pretty clear in this case that reference of Plane type holds Airbus type instance. However it's not that simple, as the Airbus instance itself could have been a method parameter, which could hold any subclass instance or Airbus instance itself.

Only safe bet is to not parse through the parent chain and take the reference for it's face value that is actual reference variable type. Another way of doing this could have been by implementing method overloading same as overriding and by using run time binding of objects for resolution. I don't know why it wasn't done this way as it would have made method overloading and overriding more uniform.

Following are the references from JLS Overloading

When a method is invoked (§15.12), the number of actual arguments (and any explicit type arguments) and the compile-time types of the arguments are used, at compile time, to determine the signature of the method that will be invoked (§15.12.2). If the method that is to be invoked is an instance method, the actual method to be invoked will be determined at run time, using dynamic method lookup (§15.12.4).

Java overloading is compile time polymorphism. So, when you declare planeAirbus as Plane, it will invoke fly(Plane).

In fact, class Main shouldn't know than Plane and Airbus can fly. Better design of it:

public interface Flyable{
  void fly();
}

public Plane implements Flyable{
  void fly(){
     //do something
  }
}

 public Airbus implements Flyable{
    void fly(){
       //do something
    }
 }

And then in Main class

public static void main(String[] args) {
  Flyable plane = new Plane();
  plane.fly();

  Flyable airbus = new Airbus();
  airbus.fly();
}