Two important things to call a method.
You have two times: compile time and runtime.
And the rules do not match between the two times.
at compile time, it must be determined statically which exact method signature is invoked to compile.
This binding is static because the compiler does not matter for the specific instance on which the method is called, and it is the same for the parameters passed to the method.
The compiler does not rely on efficient types, since at run time, effective types can change during the execution thread.
Thus, the compiler searches among the available methods for the declared type, which is a more specific method in accordance with the declared types of the parameters passed to it.
at run time, an instance method from a class or from another will be used in accordance with the effective instance on which the method is called.
But the called method must respect the signature specified at compile time.
1) For the first case:
Fox foxi = new Fox(); Dog hybrid = new Fox(); System.out.println(hybrid.play(foxi));
- First time (compilation time):
For a Dog instance, the compiler must find the most specific play() method with a variable parameter with a declared type of Fox.
In the Dog class, there is one play() method with a compatible signature:
public String play(Dog d) {
So, this signature is used for binding: String play(Dog d) .
The bark() method is very obvious, since there is only one signature of the bark () method.
Thus, we have no ambiguity in the method that is associated at compile time
At run time, the String play(Dog d) method of the specific instance is called. The hybrid variable refers to an instance of Fox, but Fox does not override String play(Dog d) . Fox defines the play () method, but with a different signature:
public String play(Fox f) {
So, the JVM calls the public String play(Dog d) { dog method.
And then it calls an efficient type d method when d.bark() is d.bark() , and d refers to the Fox instance.
So, "WuffRingding" is displayed.
2) For the second case:
Fox foxi = new Fox(); Dog hybrid = new Fox(); System.out.println(foxi.play(hybrid));
- First time (compilation time):
For a Fox instance, the compiler must find the most specific play() method with a variable parameter with a declared type of Dog .
In the Fox class, there are two play() methods with a compatible parameter:
public String play(Dog d) {
The compiler must choose a more specific method for the method call context
It identifies a more specific method than another for the Dog parameter of the declared type: public String play(Dog d) . Therefore, the compiler binds the call to the play() method to public String play(Dog d) when compiling the class.
At run time, the String play(Dog d) method of the specific instance is called.
As for the first case, the foxi variable refers to an instance of Fox, but Fox does not override String play(Dog d) .
Thus, the JVM calls the dog’s public String play(Dog d) method.
And then it calls an efficient type f method when f.bark() is f.bark() , and f refers to an instance of Fox .
This again displays "WuffRingding".
To avoid this surprise, you should add @Override in methods designed to override the method of the parent class:
For instance:
@Override public String play(Fox f) { return "Ringding" + f.bark(); }
If the method does not override the play(Fox f) method in the hierarchy, the compiler will complain about it.