I do know the syntactical difference between overriding and overloading. And I also know that overriding is run-time polymorphism and overloading is compile-time polymorphis
Every 'Greeter' class has 3 virtual methods: void greetMe()
, void greetMe(String)
, and void wishLuck()
.
When you call greeter.greetMe()
the compiler can work out which one of the three virtual methods should be called from the method signature - ie. the void greetMe()
one since it accepts no arguments. Which specific implementation of the void greetMe()
method is called depends on the type of the greeter
instance, and is resolved at run-time.
In your example it's trivial for the compiler to work out which method to call, since the method signatures are all completely different. A slightly better example for showing the 'compile time polymorphism' concept might be as follows:
class Greeter {
public void greetMe(Object obj) {
System.out.println("Hello Object!");
}
public void greetMe(String str) {
System.out.println("Hello String!");
}
}
Using this greeter class will give the following results:
Object obj = new Object();
String str = "blah";
Object strAsObj = str;
greeter.greetMe(obj); // prints "Hello Object!"
greeter.greetMe(str); // prints "Hello String!"
greeter.greetMe(strAsObj); // prints "Hello Object!"
The compiler will pick out the method with the most specific match using the compile-time type, which is why the 2nd example works and calls the void greetMe(String)
method.
The last call is the most interesting one: Even though the run-time type of strAsObj is String
, it has been cast as an Object
so that's how the compiler sees it. So, the closest match the compiler can find for that call is the void greetMe(Object)
method.