Overloading is compile-time polymorphism. Really? - java

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 polymorphism. But my question is: "Is overloading is really compile-time polymorphism? Is the method call really solving at compile time?". To clarify my point, let's consider an example class.
public class Greeter {
public void greetMe() {
System.out.println("Hello");
}
public void greetMe(String name) {
System.out.println("Hello " + name);
}
public void wishLuck() {
System.out.println("Good Luck");
}
}
Since all of the methods greetMe(), greetMe(String name), wishLuck() are public, they all can be overriden(including overloaded one), right? For example,
public class FancyGreeter extends Greeter {
public void greetMe() {
System.out.println("***********");
System.out.println("* Hello *");
System.out.println("***********");
}
}
Now, consider the following snippet:
Greeter greeter = GreeterFactory.getRandomGreeter();
greeter.greetMe();
The getRandomGreeter() method returns a random Greeter object. It may either return an object of Greeter, or any of its subclasses, like FancyGreeter or GraphicalGreeter or any other one. The getRandomGreeter() will create the objects either using new or dynamically load the class file and create object using reflection(I think it is possible with reflection) or any other way that is possible. All of these methods of Greeter may or may not be overriden in subclasses. So the compiler has no way to know whether a particular method(overloaded or not) is overriden. Right? Also, wikipedia says on Virtual functions:
In Java, all non-static methods are by default "virtual functions".
Only methods marked with the keyword final, which cannot be overridden,
along with private methods, which are not inherited, are non-virtual.
Since, virtual functions are resolved at run-time using dynamic method dispatch, and since all non private, non final methods are virtual(whether overloaded or not), they must be resolved at run-time. Right?
Then, How can overloading still be resolved at compile-time? Or, is there anything that I misunderstood, or am I missing?

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.

Overloaded methods can still be overridden, if that is what you ask.
Overloaded methods are like different families, even though they share the same name. The compiler statically chooses one family given the signature, and then at run time it is dispatched to the most specific method in the class hierarchy.
That is, method dispatching is performed in two steps:
The first one is done at compile time with the static information available, the compiler will emit a call for the signature that matches best your current method parameters among the list of overloaded methods in the declared type of the object the method is invoked upon.
The second step is performed at run time, given the method signature that should be called (previous step, remember?), the JVM will dispatch it to the most concrete overridden version in the actual type of receiver object.
If the method arguments types are not covariant at all, overloading is equivalent to having methods names mangled at compile time; because they are effectively different methods, the JVM won't never ever dispatch them interchangeably depending on the type of the receiver.

What is polymorphism?
Acc. to me: if an entity can be represented in more than one forms, that entity is said to exhibit polymorphism.
Now, lets apply this definition to Java constructs:
1) Operator overloading is compile time polymorphism.
For example, + operator can be used to add two numbers OR to concatenate two strings. it's an example of polymorphism strictly saying compile-time polymorphism.
2) Method overloading is compile time polymorphism.
For example, a method with same name can have more than one implemntations. it's also a compile-time polymorphism.
It's compile-time because before execution of program compiler decides the flow of program i.e which form will be used during run-time.
3) Method overriding is run-time polymorphism.
For example, a method with same signature can have more than one implemenations. it's a run time polymorphism.
4) Base class use in place of derived class is run time polymorphism.
For example, an interface reference can point to any of it's implementor.
It's run-time because the flow of program can't be known before execution i.e. only during run-time it can be decided that which form will be used.
I hope it clears a bit.

Overloading in this respect means that the type of the function is statically determined at compile time as opposed to dynamic dispatch.
What really happens behind the scenes is that for a method named "foo" with types "A" and "B" two methods are created ("foo_A" and "foo_B"). Which of them is to be called is determined at compile-time (foo((A) object) or foo((B) object) result in foo_A being called or foo_B). So in a way this is compile-time polymorphism, although the real method (i.e. which implementation in the class hierarchy to take) is determined at runtime.

I have strong objection to call method overloading as compile time polymorphism.
I agree that method overloading is static binding(compile time) but i didn't see polymorphism in that.
I tried to put my opinion in my question to get clarification. you can refer this link.

Related

Can method overloading be considered a way of describing polymorphism in Java?

So, I was studying from Head First Java and there I read -
An overloaded method is just a different method that happens to have the same method name, It has nothing to do with inheritance and polymorphism.
However, I have another famous book named as Java - The Complete Reference by Herbert Schildt and in that book, I read:
Method overloading is one of the ways that Java supports polymorphism. Method overloading supports polymorphism because it is one way that Java implements the “one interface, multiple methods” paradigm.
Which one of them is correct?
To answer your question in the title, no, you cannot use method overloading to describe polymorphism.
Method Overloading is when a class has two or more methods by the same name, the only difference is its parameters. This is a completely difference concept than polymporhism.
Polymorphism is the ability of an object to take on many forms. This occurs when a parent class reference is used to refer to a child class object.
For example, if I was tasked with creating some type of application for a zoo and I wanted to keep track of the animals using classes. I would make a class called "Animal" and additional classes for each animal, "Lion", "Eagle", "Dolphin". After declaring the animal classes as subclasses, I can then use the concept of polymorphism to create Lions, Eagles, and Dolphins which are of type "Animal".
Can method overloading be considered a way of describing polymorphism
in Java?
No these are two different concepts.
I think that you incorrectly understood what the author means.
I stressed in bold the important part :
Method overloading is one of the ways that Java supports polymorphism.
Method overloading supports polymorphism because it is one way that
Java implements the “one interface, multiple methods” paradigm.
It simply means that overloading and polymorphism are not incompatible.
For example, you may have an interface that defines an overloaded method :
public interface Doable{
void doX(String s);
void doX(Integer s)
}
Suppose MyDoable an implementation of it and MyChildDoable a subclass of MyDoable.
When you write :
MyDoable myDoable = new MyChildDoable();
myDoable.doX("a")
the compiler will bound the invoked method to void doX(String s); (overloading) but at runtime, the method of the instance (MyChildDoable) will be used (polymorshism).
Polymorphism is not of one type, there are different types of polymorphism. Please refer this wonderful link - Java Polymorphism to understand it better.
Overloading supports polymorphism, the polymorphic behavior invocation is based on type arguments passed and it takes place in an ad-hoc way.
So, there is this idea of compile time polymorphism and runtime polymorphism. The idea of polymorphism implies same interface but different implementations.
The way "compile time" polymorphism works is through function overloading i.e. you have the same function name but with different arrity. I am guessing this is what the second second book is referring to as "polymorphism supported through method overloading". However, strictly speaking the interface also includes the arrity, which means method overloading might not constitute polymorphism.
Runtime polymorphism is where the actual type of a given object is what dictates what implementation should be used. This is where the interface / base class and derived class comes into picture. This would be the more accurate definition of polymorphism - at least from an object orientation point of view.
Overriding - this is about polymorphism.
public class Base {
public void print() {
System.out.println("base");
}
}
public class Extend extends Base {
#Override
public void print() {
System.out.println("Extend");
}
}
Let's look at the output
new Base().print();
will print "Base"
new Extend().print();
will print "Extend".
Overloading - this is about method overload in one class with different parameters:
public class ABC {
// method 1
void method(int a){
System.out.println("method 1");
}
// method 2
void method(int a, int b){
System.out.println("method 2");
}
}
Let's look at the output
ABC abc = new ABC();
abc.method(5);
will invoke method(int) and print "method 1"
abc.method(1,2)
will invoke method(int, int) and print "method 2"
Overriding - this is runtime feature;
Overloading - this compile time feature;
all overloading method (with one name) must be same return type or void.

Confusing polymorphism in Java

Consider this code (complete class, runs fine, all classes in one class for the sake of brevity).
My questions are after the code listing:
import java.util.LinkedList;
import java.util.List;
class Gadget {
public void switchon() {
System.out.println("Gadget is Switching on!");
}
}
interface switchonable {
void switchon();
}
class Smartphone extends Gadget implements switchonable {
#Override
public void switchon() {
System.out.println("Smartphone is switching on!");
}
}
class DemoPersonnel {
public void demo(Gadget g) {
System.out.println("Demoing a gadget");
}
public void demo(Smartphone s) {
System.out.println("Demoing a smartphone");
}
}
public class DT {
/**
* #param args
*/
public static void main(String[] args) {
List<Gadget> l = new LinkedList<Gadget>();
l.add(new Gadget());
l.add(new Smartphone());
for (Gadget gadget : l) {
gadget.switchon();
}
DemoPersonnel p = new DemoPersonnel();
for (Gadget gadget : l) {
p.demo(gadget);
}
}
}
Questions:
From the compilers point of view, what is the origin of the switchon method in Smartphone? Is it inherited from the base class Gadget? Or is it an implementation of the switchon method mandated by the switchonable interface? Does the annotation make any difference here?
In the main method, first loop: Here, we see a case of runtime polymorphism - i.e., when the first for loop is running, and gadget.switchon() is called, it first prints "Gadget is switching on", and then it prints "Smartphone is switching on". But in the second loop, this runtime resolution does not happen, and the output for both calls to demo is "Demoing a gadget", whereas I was expecting it to print "Demoing a gadget" the first iteration, and "Demoing a smartphone" the second time.
What am I understanding wrong? Why does the runtime resolve the child class in the first for loop, but doesn't do so in the second for loop?
Lastly, a link to a lucid tutorial on runtime/compile-time polymorphism in Java will be appreciated. (Please do not post the Java tutorial trail links, I didn't find the material particularly impressive when discussing the finer nuances in respectable depth).
This is how it works shortly:
Compiling time
The compiler defines the required signature for the requested method
Once the signature is defined, the compiler starts to look for it in the type-Class
If it finds any compatible candidate method with the required signature proceeds, otherwise returns an error
Runtime
During execution JVM starts to look for the candidate method with the signature as exactly defined during the compiling-time.
The search for the executable method actually starts from the real Object implementation Class (which can be a subclass of the type-Class) and surf the whole hierarchy up.
Your List is defined with type Gadget.
for (Gadget gadget : l) {
gadget.switchon();
}
When you ask for gadget.switchon(); the compiler will look for the switchon() method in the Gadget class and as it's there the candidate signature is simply confirmed to be switchon().
During the execution, the JVM will look for a switchon() method from the Smartphone Class and this is why it is displaying the correct message.
Here is what happens in the second for-loop
DemoPersonnel p = new DemoPersonnel();
for (Gadget gadget : l) {
p.demo(gadget);
}
The signature in this case is for both objects demo(Gadget g), this is why for both iterations method demo(Gadget g) is executed.
Hope it helps!
From the compilers point of view, what is the origin of the switchon method in Smartphone? Is it inherited from the base class Gadget? Or is it an implementation of the switchon method mandated by the switchonable interface?
The second case
Does the annotation make any difference here?
Not at all, #Override is just a helper, whe you use it you are telling the compiler: "my intention is to override the method from a supertype, please throw an exception and don't compile this if it is not overriding anything"
About the second question, in this case the method that better match acording to its signature is the one to be called. At run time in the second loop your objects have the supertype "associated", that's the reason public void demo(Gadget g) will be called rather than public void demo(Smartphone g)
1.It shouldn't matter. Because it is extending Gadget, if you don't override and call switchon() from a smartphone, it would say "Gadget is switching on!". When you have both an interface and a parent class with the same method, it really doesn't matter.
2.The first loop works and the second doesn't because of the way java looks at objects. When you call a method from an object, it takes the method directly from that object, and thus knows whether smartphone or gadget. When you send either a Smartphone or Gadget into an overloaded method, everything in that class is called a Gadget, whether it is actually a smartphone or not. Because of this, it uses the gadget method. To make this work, you would want to use this in the demo(Gadget g) method of DemoPersonnel:
if(gadget instanceof Smartphone){
System.out.println("Demoing a gadget");
}else{
System.out.println("Demoing a smartphone");
}
Sorry I don't have a link to a tutorial, I learned through a combination of AP Computer Science and experience.
Answering question 2 first: In the second loop your passing an object typed as a Gadget therefore the best match in the demo class is the method taking a gadget. this is resolved a compile time.
for question 1: the annotation does not make a difference. it just indicates that you overriding (implementing) method in the interface.
For compiler, Smartphone inherits switchon() method "implementation" from Gadget and then Smartphone overrides inherited implementation with its own implementation. On the other hand switchonable interface dictates Smartphone to provide an implementation of switchon() method definition and which was fulfilled by the implementation overridden in Smartphone.
First case is working as you expected because it is indeed a case of polymorphism i.e. you have one contract and two implementations - one in Gadget and another in Smartphone; where later has "overridden" the former implementation. Second case "should not" work as you expect it to, because there's only one contract and one implementation. Do note that you are "not overriding" the demo() method, you are actually "overloading" the demo() method. And, overloading means two "different" unique method definitions that only shares the "same name". So, it is a case of one contract and one implementation, when you call demo() with Gadget parameter, because compiler will match the method name with exact method parameter type(s) and by doing so will call "different methods" in both iterations of the loop.
about the second question :
In Java, dynamic method dispatch happens only for the object the method is called on, not for the parameter types of overloaded methods.
Here is a link to the java language specification.
As it says :
When a method is invoked (§15.12), the number of actual arguments (and
any explicit type arguments) and the compile-time types of the
arguments are used, at compile time, to determine the signature of the
method that will be invoked (§15.12.2). If the method that is to be
invoked is an instance method, the actual method to be invoked will be
determined at run time, using dynamic method lookup (§15.12.4).
so basically :the compile time type of the method parameters is used to determine the signature of the method to be called
At runtime, the class of the object the method is called on determines which implementation of that method is called, taking into account that it may be an instance of a subclass of the declared type that overrides the method.
In your case when you create object of a child class by new child(); and pass it on to the overloaded method, it has superclass type associated. Hence overloaded method with parent's object is called.
The annotation does not make any difference here. Techinically is like you are doing both things: overriding parent switchon() and implementing the switchon() interface method in one shot.
Method lookup (with respect to method arguments) is not done dynamically (at runtime) but statically at compile-time. Looks strange but thats how it works.
Hope this helps.
The compiler selects a method signature based on the declared type of the "this" pointer for the method and the declared type of the parameters. So since switchon receives a "this" pointer of Gadget, that is the version of the method that the compiler will reference in its generated code. Of course, runtime polymorphism can change that.
But runtime polymorphism only applies to the method's "this" pointer, not the parms, so the compiler's choice of method signature will "rule" in the second case.

How to prevent a method from overloading in Java?

Overriding a method can be prevented by using the keyword final, likewise how to prevent overloading?
You can't. Because it's almost pointless.
If you want to overload the method handle(..) but you are disallowed to, you'd create doHandle(..) instead.
Which overloaded method is used is determined at compile time (in contrast to overridden methods, which are determined at runtime). So the point of overloading is sharing a common name for common operations. Disallowing that is a matter of code-style, rather than anything else.
You can't do that in Java.
An overloaded method is basically just another method.
An attempt could look (something) like this
void yourMethod(String arg) { /* ... */ }
void yourMethod(String arg, Object... prevent) {
throw new IllegalArgumentException();
}
but it won't work since Java resolves overloading by looking at the "best match" or "most specific signature".
The method could still be overloaded with a
void yourMethod(String arg, String arg2) { /* ... */ }
which would be called when doing yourMethod("hello", "world").
Btw, why would you want to prevent overloading? Perhaps there is another way of doing what you want?
Err... what's the point in not allowing to Overload the method?
Protection from Overriding is allowed because it can be done by another programmer who is supposedly working on another part of code and his class is inherited from your class.
Overloading is done in the same class and is logically supposed to be done by a programmer who knows this code and is working on the same part of the code. So, if he knows this code (theoretically) and there is some inherent danger in overloading, then he should know this already because he knows the code.
That said, overloading cannot be stopped as others have already described.
Mark the class final and it can't be extended. That may defeat some other purpose though.
If you overload a method, you've created a method with the same name but different parameter types. In Java, a method is defined (partly) in terms of its parameters, and thus if two methods have the same name but different parameters, then they are apples and oranges, i.e., not the same. In short, you can't prevent someone from creating new methods in a class, which is essentially what you're asking for.
simple! don't call that overloaded method.
public class Test
{
public void m(int a)
{
*your definition*
}
public void m(float a)
{
*your definition*
}
}
public static void main(Strings [] args)
{
Test t=new Test();
t.m(5);
}
Overriding and Overloading are different techniques. Overloading is a way of declaring multiple methods with the same names but different parameter types or different no of parameters.
You can prevent a method from being overwritten by making it final, but you cannot prevent a method from being overloaded. Well technically you could make the class itself final, so that no methods at all can be added by creating a subclass but I don't think that's a good design.

Java overloading and overriding

We always say that method overloading is static polymorphism and overriding is runtime polymorphism. What exactly do we mean by static here? Is the call to a method resolved on compiling the code? So whats the difference between normal method call and calling a final method? Which one is linked at compile time?
Method overloading means making multiple versions of a function based on the inputs. For example:
public Double doSomething(Double x) { ... }
public Object doSomething(Object y) { ... }
The choice of which method to call is made at compile time. For example:
Double obj1 = new Double();
doSomething(obj1); // calls the Double version
Object obj2 = new Object();
doSomething(obj2); // calls the Object version
Object obj3 = new Double();
doSomething(obj3); // calls the Object version because the compilers see the
// type as Object
// This makes more sense when you consider something like
public void myMethod(Object o) {
doSomething(o);
}
myMethod(new Double(5));
// inside the call to myMethod, it sees only that it has an Object
// it can't tell that it's a Double at compile time
Method Overriding means defining a new version of the method by a subclass of the original
class Parent {
public void myMethod() { ... }
}
class Child extends Parent {
#Override
public void myMethod() { ... }
}
Parent p = new Parent();
p.myMethod(); // calls Parent's myMethod
Child c = new Child();
c.myMethod(); // calls Child's myMethod
Parent pc = new Child();
pc.myMethod(); // call's Child's myMethod because the type is checked at runtime
// rather than compile time
I hope that helps
Your are right - calls to overloaded methods are realized at compile time. That's why it is static.
Calls to overridden methods are realized at run-time, based on the type on which the method is invoked.
On virtual methods wikipedia says:
In Java, all non-static methods are by default "virtual functions." Only methods marked with the keyword final are non-virtual.
final methods cannot be overridden, so they are realized statically.
Imagine the method:
public String analyze(Interface i) {
i.analyze();
return i.getAnalysisDetails();
}
The compiler can't overload this method for all implementations of Interface that can possibly be passed to it.
I don't think you can call overloading any sort of polymorphism. Overloaded methods are linked at compile time, which kind of precludes calling it polymorphism.
Polymorphism refers to the dynamic binding of a method to its call when you use a base class reference for a derived class object. Overriding methods is how you implement this polymorphic behaviour.
i agree with rachel, because in K&B book it is directly mentioned that overloading does not belong to polymorphism in chapter 2(object orientation). But in lots of places i found that overloading means static polymorphism because it is compile time and overriding means dynamic polymorphism because it s run time.
But one interesting thing is in a C++ book (Object-Oriented Programming in C++ - Robert Lafore) it is also directly mentioned that overloading means static polymorphism.
But one more thing is there java and c++ both are two different programing languages and they have different object manipulation techniques so may be polymorphism differs in c++ and java ?
Method Overloading simply means providing two separate methods in a class with the same name but different arguments while method return type may or may not be different which allows us to reuse the same method name.
But both methods are different hence can be resolved by compiler at compile time that's is why it is also known as Compile Time Polymorphism or Static Polymorphism
Method Overriding means defining a method in the child class which is already defined in the parent class with same method signature i.e same name, arguments and return type.
Mammal mammal = new Cat();
System.out.println(mammal.speak());
At the line mammal.speak() compiler says the speak() method of reference type Mammal is getting called, so for compiler this call is Mammal.speak().
But at the execution time JVM knows clearly that mammal reference is holding the reference of object of Cat, so for JVM this call is Cat.speak().
Because method call is getting resolved at runtime by JVM that's why it is also known as Runtime Polymorphism and Dynamic Method Dispatch.
Difference Between Method Overloading and Method Overriding
For more details, you can read Everything About Method Overloading Vs Method Overriding.
Simple Definition - Method overloading deals with the notion of having two or more methods(functions) in the same class with the same name but different arguments.
While Method overriding means having two methods with the same arguments, but different implementation. One of them would exist in the Parent class (Base Class) while another will be in the derived class(Child Class).#Override annotation is required for this.
Check this :
Click here for a detailed example
Property Over-loading Overriding
Method Names -------------->must be Same----------------must be same
Arg Types------------------>must be Different(at least arg)
Method Signature
Return Type
Private,Static,Final
Access Modifier
try/Catch
Method Resolution
First, I want to discuss Run-time/Dynamic polymorphism and Compile-time/static polymorphism.
Compile-time/static polymorphism:- as its name suggests that it bind the function call to its appropriate Function at compile time. That means the compiler exactly know which function call associated to which function. Function overloading is an example of compile time polymorphism.
Run-time/Dynamic polymorphism:-In this type of polymorphism compiler don't know which functions call associates to which function until the run of the program. Eg. function overriding.
NOW, what are the function overriding and function overloading???
Function Overloading:- same function name but different function signature/parameter.
eg. Area(no. of parameter)
{ -------------
----------------
return area;}
area of square requires only one parameter
area of rectangle requires two parameters(Length and breadth)
function overriding:- alter the work of a function which is present in both the Superclass and Child class.
eg. name() in superclass prints "hello Rahul" but after overring in child class it prints "hello Akshit"
Tried to cover all differences
Overloading Overriding
Method Name Must be same Must be same
Argument Types Must be same Must be different
Return Type No restriction Must be same till 1.4V
but after 1.4V
co- variants
were introduced
private/static/final Can be overloaded Cannot be overridden
Access Modifiers No restriction Cannot reduce the scope
Throws keyword No restriction If child class method
throws a checked
exception the parent
class method must throw
the same or the
parent exception
Method Resolution Taken care by compiler Taken care by JVM based
based on reference types on run-time object
Known as Compile-Time Polymorphism, RunTime Polymorphism,
Static Polymorphism, or dynamic polymorphism,
early binding late binding.

How does Java pick which overloaded function to call?

This is a purely theoretical question.
Given three simple classes:
class Base {
}
class Sub extends Base {
}
class SubSub extends Sub {
}
And a function meant to operate on these classes:
public static void doSomething(Base b) {
System.out.println("BASE CALLED");
}
public static void doSomething(Sub b) {
System.out.println("SUB CALLED");
}
It seems that the followign code:
SubSub ss = new SubSub();
doSomething(ss);
could legitimately result in printing either BASE CALLED, or SUB CALLED, since SubSub can be casted to both of those. In fact, removing the Sub version of the function causes BASE CALLED to be printed. What actually happens is that "SUB CALLED" is printed. This seems to mean that which function is called doesn't depend on the order the functions are defined in, as the Base version was called first.
Does Java just look at all the different versions of the function and pick the one which requires the smallest traversal up the inheritance stack? Is this standardized? Is it written out in any documentation?
The formal specification can be found in part 15.12.2.5 of the Java Language Specification (JLS). Thanks to generics this is pretty complicated, so you might want to look at same section of the first edition of the JLS.
It basically says that the compiler tries to find a version of the method where all parameters including the object the method is called upon are most specific. If no such method exists (e.g. since you have method(Base, Sub) and method(Sub, Base) but not method(Sub, Sub)), then the compilation fails.
Note that the actual choice of method depends on the dynamic type of the target object for instance methods, but not for the parameters. Your example would still work the same on the instance level.
You should be able to give the compiler a helping hand by casting or redeclaring the type of ss. If the declared type of the variable matches a signature exactly then everything is clear for the compiler and maintenance programmers as well. It doesn't matter if you then assign a more specific type as long as the declared type matches.
As far as I know, Java and C++ make this decision at compilation time (since these are static functions that are not dynamically dispatchable) based on the most specific matching that they can make. If your static type is SubSub and you have an overload that takes SubSub, this is the one that will be invoked. I'm fairly sure it's in both standards.
If you have a reference or pointer to Base, even if it contains a Sub or a SubSub, you will match the version that takes a Base because at compile time, that is the only assurance that the compiler has.
When you have overloaded static methods then it calls that method that is defined immediately in the class which is invoking the method. If however, no method is defined in the calling class then it will invoke the method inherited from its immediate parent class.
In your case there are two overloaded methods both of which can accept SubSub as parameter. the compiler checks for the most specific match and goes for it. But the most specific match is generally the lowest in the type hierarchy.
EDITED
Removed the conflicting statement. Two methods in classes that are at the same type hierarchy level can't be in ambiguous state for the compiler to choose. This ambiguity is possible only in the case of multiple inheritance.
Java binds methods dynamically (in runtime, depending on object instance type, not reference type) but only in context of one method signature. Java binds method signature statically (at compilation time).
In other words, Java makes decision what method (signature) should be called in compile time (statically - reference based - overloading). In runtime Java will take that signature, find proper object in object type hierarchy and execute that method on that dynamically binded object.
Overloading -> what (method signature at compilation time)
Overriding -> from where (object in type hierarchy at runtime)

Categories