Simple question, strange result. I have two classes A
and B
:
public class A
{
protected int num;
public A(int n)
{
num = n;
}
public boolean f(A a)
{
return num == a.num * 2;
}
}
public class B extends A
{
public B(int n)
{
super(n);
}
public boolean f(B b)
{
return num == b.num;
}
}
Why does y1.f(y2)
call the f()
method in A
instead of in B
?
A y1 = new B(10);
B y2 = new B(10);
System.out.println(y1.f(y2));
Is it not supposed to call f()
in B
as B
is more specific than A
?
Why does y1.f(y2) calls the f() method in A instead of in B?
Because the compile-time type of y1
is A
.
Overloading is performed at compile-time... the execution-time type of the object you call the method on is only relevant for overriding.
So the compiler is choosing the method f(A)
as that's the only f
method it's aware it can call on y1
(and it's checked that it's applicable given the argument list). That method isn't overridden in B
, therefore at execution time, the implmenetation in A
is called.
As a starker example, consider this code:
Object x = "foo";
int length = x.length();
This won't even compile, because Object
doesn't contain a length()
method. String
does, but the compiler doesn't consider that, because the compile-time type of x
is Object
, not String
- even though we can tell that at execution time, the value of x
will be a reference to a String
object.
See more on this question at Stackoverflow