Здесь происходит две вещи:
- Перегрузка
- Перекрытие
Перегрузка означает наличие двух разных методов в одном классе с одинаковым именем, но с разными типами аргументов (поэтому они разные). Переопределение и полиморфизм означает наличие одного и того же метода в двух разных классах.
Классы A
и B
оба перегрузка метод foo
: у них есть два метода с одинаковым именем. В A
один метод принимает Object
в качестве параметра, а другой - A
в качестве параметра. В B
в качестве параметра принимается A
, а в B
. Из этих четырех методов два одинаковы (foo(A)
).
Метод foo(A)
в B
переопределяет метод foo(A)
в A
. Однако метод foo(B)
- это другой метод.
Поэтому, когда вы вызываете a2.foo(b)
, вы вызываете метод foo(A)
. Должно быть, так как a2
объявлен как A
, а A
не имеет A.foo(B)
. Поскольку a2
на самом деле является объектом типа B
, вы вызываете B.foo(A)
, поскольку он переопределяет A.foo(A)
.