Akshaya Amar
Akshaya Amar

Reputation: 179

In method overloading, is method resolution takes place at compile time or run time?

As per my knowledge if a method is non - static and non - private, then invokevirtual instructions are added in the bytecode which results in dynamic binding at runtime, but in the following program why the compile time binding is being done.

class Fruit{

}

class Apple extends Fruit{

}

class MyTest{
  public void show(Fruit f){
    System.out.println("fruit");
  }

  public void show(Apple a){
    System.out.println("apple");
  }

  public static void main(String[] args) {
    MyTest t = new MyTest();

    Fruit f = new Fruit();
    t.show(f);

    Apple a = new Apple();
    t.show(a);

    Fruit f1 = new Apple();
    t.show(f1);
  }
}

The output of the following program is

Fruit 
Apple 
Fruit

I have a doubt in this following line of code

Fruit f1 = new Apple(); 
t.show(f1);

because show() is an instance method which results in invokevirtual and in case of invokevirtual, the late binding is done based on the type of object, so accordingly it should print "Apple", then why the result is "Fruit" which is based on type of reference.

Please correct me where I am wrong and what knowledge I am lacking for dynamic and compile time binding or any misconception I have related to this concept.

Upvotes: 2

Views: 437

Answers (2)

khelwood
khelwood

Reputation: 59146

It is a virtual method call, but the virtual method is owned by MyTest, not by Fruit. The overriding would have to take place in the owner of the method, not in a class that is being passed as an explicit argument to the method.

Overriding uses the runtime type of the owner of the method being called; whereas resolving overloads (based on the explicit arguments to the method) takes place at compile time, so it depends on the declared compile-time type of the arguments.

If you added a show() method to Fruit, you could override it in Apple and it would be the Apple one that was called.

E.g.

Fruit f = new Apple();
f.show(); // calls Apple.show, if it exists

Upvotes: 5

rzwitserloot
rzwitserloot

Reputation: 103229

Java does both, depending on the situation.

Specifically, it does the 'late binding' only on the receiver, not on the parameters.

So, given:

   class Fruit {
       void show(Fruit other) {
           System.out.println("I am fruit, and that is also Fruit");
       }
       void show(Apple other) {
           System.out.println("I am fruit, and that is Apple");
       }
   }
   class Apple extends Fruit {
       void show(Fruit other) {
           System.out.println("I am Apple, and that is Fruit");
       }
       void show(Apple other) {
           System.out.println("I am Apple, and that is also Apple");
       }
   }
   Fruit x = new Apple();
   Fruit y = new Apple();
   x.show(y);

Then show(Fruit) is called and not show(Apple) because no late binding is applied to parameter types. However, if the Apple class has its own show(Fruit) method (this is then called: It overrides the show(Fruit) method from Fruit), that will late bind, so Apple's impl of show is chosen and not Fruit's impl.

Thus, the above prints: "I am Apple, and that is Fruit".

Upvotes: 3

Related Questions