Reputation: 85
I have a simple code, I want to know why and how some methods are chosen over the others :
class A :
public class A {
int f(A aa){
return 1;
}
}
class B :
public class B extends A {
int f(A aa){
return 2;
}
int f(B bb){
return 3;
}
}
Test :
public class Test {
public static void main(String[] args) {
A a = new A();
A ab = new B();
B b = new B();
System.out.println(a.f(a));
System.out.println(a.f(ab));
System.out.println(a.f(b));
System.out.println(ab.f(a));
System.out.println(ab.f(ab));
System.out.println(ab.f(b));
System.out.println(b.f(a));
System.out.println(b.f(ab));
System.out.println(b.f(b));
}
}
Now, the output of this program is as below :
1
1
1
2
2
2
2
2
3
Now, can you please tell me why System.out.println(ab.f(b))
gave 2 as output ?
Upvotes: 3
Views: 69
Reputation: 34628
Overload resolution is done at compile time. Overrides are used at runtime.
This means that at compile time, the compiler decides which of all the method signatures is appropriate for the method invocation. Then, at runtime, if that method with that signature is overridden in the run-time object being used, the overridden method is used.
At compile time, only the static type of the variable is known. That is, only method signatures that are associated with the declared type of the variable are considered.
In this case, the variable ab
is declared to be A
. Therefore, only method signatures that exist in A
are considered for the call ab.f(b)
. The only f
in type A
is the f(A aa)
method. The call is legal for this method signature, so the code generated by the compiler says "at this point, call the method f
that has a single parameter of type A
, and pass b
as the parameter to it."
When runtime comes, since ab
is actually a B
instance, the method f
that has a single parameter of type A
is actually overridden in it, so it will print 2
, rather than 1
.
Contrast this with b.f(b)
. Here the declared type of the variable b
is B
. Therefore it has two overloads of the method f
- one with a B
parameter and one with an A
. At compile time, it already knows that the argument b
is declared B
. So the most specific overload is f(B bb)
. The invocation is translated into "call the f
with a single parameter of type B
". And at runtime, this prints 3.
The difference? At compile time, ab
was of type A
and f(B bb)
doesn't exist in that type. b
was of type B
, and f(B bb)
exists and is the most specific overload.
Upvotes: 2
Reputation: 46323
ab
is an instance of class B
, as such, it overrides int f(A aa)
to return 2.
The reason f(A aa)
is executed, and not f(B bb)
is that ab
is a variable of type A
. As such, there is no f(B bb)
available to be called so f(A aa)
is matched (b
of type B
inherits A
).
Although the value of ab
is indeed an object of type B
, the compiler can't assume that, and certainly can't call functions that don't exist for the declared type of the variable.
Upvotes: 0
Reputation: 362
ab is a static variable of class A. while initializing as a dynamic instance of B, the method f in class A is overridden.
Now when calling ab.f(b)
it "goes" to class A (to the static value) and looks for f ,which now returns 2.
Upvotes: 0