Overloading method on extended class

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?

Jon Skeet
people
quotationmark

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.

people

See more on this question at Stackoverflow