Этот пример кода довольно запутан, потому что, хотя цель состоит в том, чтобы продемонстрировать переопределение , он фактически демонстрирует перегрузку .
Поскольку B.m3(int)
не соответствует сигнатуре A.m3(Object)
(см. JLS 8.4.8.1 ), метод не переопределяется . Вместо этого он перегружен .
Но почему вызов метода с аргументом int
не выбирает правильный? В этой упрощенной версии кода:
A ab = new B();
ab.m3(2);
аргумент m3
является int
, поэтому похоже, что подпись должна соответствовать B.m3(int)
. Тем не менее, как правильно указано в вопросе, это A.m3(Object)
, который называется. Причина в том, что в случаях перегрузки выбор метода основан на статическом типе ссылки на объект , а не на тип времени выполнения, как для переопределения.
Поскольку статический тип ab
равен A
, алгоритм выбора метода начинает поиск метода m3
в классе A
. Единственное, что он находит, это m3(Object)
, но из-за автобокса аргумент может быть адаптирован для соответствия сигнатуре, поэтому код компилируется.
Так что, если вы измените код и просто объявите ab
типа B
:
B ab = new B();
ab.m3(2);
тогда, удивительно, это B.m3(int)
, что называется.
Из-за этой потенциальной глубокой путаницы эту ситуацию следует избегать любой ценой, и для ее помощи доступно множество инструментов и функций. @Override
является одним из примеров. Многие IDE также имеют декорации желоба для обозначения переопределения (как показано ниже с зеленым треугольником для Eclipse).