Unclear about dynamic binding
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.