Reputation: 179
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
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
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