I am not understanding the concept of dynamic binding and overriding properly:
Here is some code:
class Cake {
public void taste (Cake c) {
System.out.println("In taste of Cake class");
}
}
class ChocolateCake extends Cake {
public void taste(Cake c) {
System.out.println("In taste (Cake version) of ChocolateCake class");
}
public void taste(ChocolateCake cc) {
System.out.println("In taste (ChocolateCake version) of ChocolateCake class");
}
}
public static void main(String[] args)
{
ChocolateCake cc = new ChocolateCake();
Cake c = new ChocolateCake();
Cake c1 = new Cake();
Cake c2 = new ChocolateCake();
c1.taste(cc);
c1.taste(c);
c2.taste(cc);
c2.taste(c);
}
I expected:
In taste of Cake class
In taste of Cake class
In taste (ChocolateCake version) of ChocolateCake class" <----
In taste (Cake version) of ChocolateCake class
Actual:
In taste of Cake class
In taste of Cake class
In taste (Cake version) of ChocolateCake class <----
In taste (Cake version) of ChocolateCake class
If the object is of type ChocolateCake and I call cc which is also ChocolateCake, how come the compiler shows it's getting Cake as a parameter?
The binding which can be resolved by the compiler using runtime is known as static binding. For example, all the final, static, and private methods are bound at run time. All the overloaded methods are binded using static binding. The concept of dynamic binding removed the problems of static binding.
Java 8Object Oriented ProgrammingProgramming In dynamic binding, the method call is bonded to the method body at runtime. This is also known as late binding. This is done using instance methods.
Let us take an example of dynamic binding in the case of multilevel inheritance. In this example, we have two levels of inheritance is taken into account. In this example, we will show how the method identifies () is displaying different messages depending on which type of object it is associated with.
On examining this statement, we can understand that dynamic binding allows us to handle different objects using just a single function name. This reduces code complexity and also enables the programmer to have an easier time while debugging. We have talked about dynamic binding in C++ a lot.
This is because Java uses both static and dynamic binding to choose a method to call in this case.
The line in question is this, right?
c2.taste(cc);
The compiler first chooses which method to call (static binding). Since c2
is of compile time type Cake
, the compiler only sees the taste(Cake)
method. So it says "call taste(Cake)
".
Now at runtime, the runtime needs to choose which implementation of taste(Cake)
to call, depending on the runtime type of c2
. This is dynamic binding. Does it choose the one in Cake
? Or the one in ChocolateCake
? Since c2
is of runtime type ChocolateCake
, it calls the implementation of taste(Cake)
in ChocolateCake
.
As you can see, the method that you thought would be called - taste(ChocolateCake)
- is not even mentioned! This is because that is a different overload of the taste
method, and because it is in the ChocolateCake
class, which the compiler can't see. Why can't the compiler see? Because c2
is of compile time type Cake
.
In short, the compiler decides which overload, the runtime decides which implementation.
Responding to your statement:
if the object is of type ChocolateCake ...
Only you know the object is of type ChocolateCake
. The compiler does not. It only knows c2
is of type Cake
because that's what its declaration says.
Since the reference type of the c2
variable is Cake
the taste
method having the Cake
type parameter will be called.
This is because the Cake
type does not have the taste
method which takes a ChocolateCake
instance, so you can't invoke that method from a Cake
type reference variable.
Now secondly, in Java due to the mechanism of runtime polymorphism the overridden taste
method of the ChocolateCake
is being called instead of the version declared in the parent Cake
class. This is due to fact at runtime the object which the Cake
reference is pointing to, will be examined and the taste
version of that particular instance will be invoked.
So due to the combination of these two effects you see that output.
If you change the reference type of c2
to ChocolateCake
you would see that the output is:
In taste (ChocolateCake version) of ChocolateCake class
when you invoke c2.taste(cc);
, since now both the compiler and runtime agrees to call that taste(ChocolateCake cc)
method in particular.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With