Метод перегрузки в расширенном классе

Простой вопрос, странный результат. У меня есть два класса A и 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;
    }
}

Почему y1.f(y2) вызывает метод f() в A вместо B?

A y1 = new B(10);
B y2 = new B(10);

System.out.println(y1.f(y2));

Не предполагается ли вызов f() в B, поскольку B более конкретный, чем A?

Ответы

Ответ 1

Почему y1.f(y2) вызывает метод f() в вместо B?

Поскольку тип времени компиляции y1 равен A.

Перегрузка выполняется во время компиляции... тип выполнения объекта, для которого вы вызываете метод, применим только для переопределения.

Таким образом, компилятор выбирает метод f(A) как единственный метод f, который, как он знает, может вызывать y1 (и он проверял его применимость, учитывая список аргументов). Этот метод не переопределяется в B, поэтому во время выполнения вызывается имменметализация в A.

В качестве примерного примера рассмотрите этот код:

Object x = "foo";
int length = x.length();

Это даже не компилируется, потому что Object не содержит метода length(). String делает, но компилятор не считает это, потому что тип x времени компиляции Object, а не String - хотя мы можем сказать, что во время выполнения значение x будет ссылкой на объект String.