Как используется мультиметодный выбор в этом примере Java?

class HelloWorld{

    public static void main(String []args){
        A j = new B();
        B k = new B();

        System.out.println(j.foo(k));
    }
}

class A {
public int foo(A p) { return 1; }
}
class B extends A {
public int foo(A p) { return 2; }
public int foo(B p) { return 3; }
}

Таким образом, на выходе будет 2. Я не понимаю, как это так. Не будет ли объект j рассматриваться как его скомпилированная форма: A ? Тем не менее, он выполняет класс B версии foo, используя параметр типа A, хотя k относится к классу B как во время компиляции, так и во время выполнения. Почему это так?


person tsquared    schedule 22.10.2016    source источник
comment
Можете ли вы предоставить минимальный воспроизводимый пример с упором на минимальный? Класс C и локальные переменные i, l и m не имеют отношения к вашему вопросу. (И смущает людей)   -  person Erwin Bolwidt    schedule 22.10.2016
comment
Я прошу прощения за то. Я создал C и другие переменные для целей тестирования, но пока не использовал их. С тех пор я сделал редактирование только с полезной информацией.   -  person tsquared    schedule 22.10.2016
comment
Поскольку вы заменили foo(A p) на B, вы не можете вызывать foo(A p) из A для объекта, который имеет тип времени выполнения (или динамический) ( B (переменная j имеет статический тип A и тип времени выполнения B). Но поскольку вы обращаетесь к j через статический тип A, вы можете вызывать только методы, определенные в A, поэтому foo(B p) недоступен.Вот почему вызывается foo(A p) класса B.   -  person Turing85    schedule 22.10.2016
comment
Ключом к пониманию этого случая является понимание того, что Java разрешает сигнатуры методов во время компиляции и реализацию методов во время выполнения. j объявлен как тип A, и у A нет метода типа 'foo(B)'. Однако B совместим по присваиванию с A, поэтому во время компиляции он выбирает foo(A). Таким образом, во время выполнения он сканирует объект типа B на наличие метода с сигнатурой foo(A). Несмотря на то, что у B есть метод с именем foo(B), он никогда не будет смотреть на него из-за решений, принятых во время компиляции.   -  person Chris K    schedule 22.10.2016
comment
Этот вопрос был помечен как дубликат с другим вопросом, который шире этого вопроса, и трудно получить четкий ответ на этот вопрос из упомянутого вопроса.   -  person Chris K    schedule 22.10.2016
comment
Ах, хорошо, спасибо вам обоим! Я не думаю, что полностью понял, как работает выбор времени компиляции! Если бы у A теоретически был метод foo(B), я предполагаю, что он смог бы выбрать Bs версию foo(B)?   -  person tsquared    schedule 22.10.2016
comment
@ Тейлор, это правильно. Попробуйте, я предсказываю, что он изменится с печати 2 на 3.   -  person Chris K    schedule 22.10.2016
comment
@ChrisK Совершенно ясно. Более широкие вопросы лучше дублируют цель, потому что они шире и лучше объясняют проблему. Это концепция канонического вопроса о переполнении стека.   -  person Tunaki    schedule 22.10.2016
comment
Следующий вопрос SO содержит описание времени компиляции и разрешения времени выполнения. stackoverflow .com/questions/1572322/   -  person Chris K    schedule 22.10.2016