This problem presented itself when me and my friends were studying for exams. We noticed strange behavior when calling a statically assigned variable’s method.
Code>Words so here we go:
class C {
public void a(double x) {}
}
class D extends C {
void b() {}
}
class F extends D {
void a(int i) {}
void a(double d) {}
Now, doing
D foo = new F();
foo.a(1);
What will this give? Well.. it runs method a(double) in F !!
This is what we thought happened:
- Program start by looking for a in static type D: nothing there.
- Goes to its super class, C. Does not find a(int) but instead finds a(double).
- Decides that this is the signature i meant (i.e. a(double)), but FIIRST, after all this search let’s look at the dynamic type first it says!
- Runs a(double) in F!
Is this correct? This means that it climbed the hierarchy to find some method that could fit if type conversion from int to double is done.. AFTER this it checks to see if the dynamic type has this newly interpreted signature.
I noticed that if I added
void a(int) {}
** in class C, it would give me a(int) in F when running the invocation above!
Can someone please explain the mechanics involved in this process? Why is so that the code runs/compiles this way? What’s the technical reasons behind this? And are there any more things one should be aware of concerning similar cirumstances ()
The reason is because Java is statically typed. Dispatch on argument type is done at compile time, not runtime.
When the code is compiled, the compiler sees that you are invoking a method named
aon an object of static typeD. It looks for compatible methods inD, and finds a single method (inherited fromC). It generates code to perform a virtual call toC.a(double).At runtime, the virtual call dispatches on the actual type of the object (not the arguments!), so it ends up calling
F.a(double), since this overridesC.a(double).The fact that the runtime type of the object is
FandFhappens to have a different method that would have been valid if it were known at compile time is irrelevant. If you want this behavior, you need reflection.If you added
C.a(int), the compiler would see two different methods namedainD, and based on the overloading rules, choose the one that takes an int.