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:
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 a
on an object of static type D
. It looks for compatible methods in D
, and finds a single method (inherited from C
). It generates code to perform a virtual call to C.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 overrides C.a(double)
.
The fact that the runtime type of the object is F
and F
happens 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 named a
in D
, and based on the overloading rules, choose the one that takes an int.
The method to call is resolved at compile time, not runtime. Since the compiler only knows at compile time that foo is a D
, and therefore only has a method a(double)
, that is the method which is called. Precisely which object's a(double)
to call is done dynamically (at runtime) however, which is why F.a(double)
will be called and not C.a(double)
.
This is called single dispatch: the method to call is dynamic on the object it is being invoked on, but static on its argument types.
If you removed that method in C
entirely, it wouldn't call a(int)
in F
, it would just fail to compile saying that it can't find that method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With