Это происходит потому, что вы не переопределяете метод 'pro c' в классе Z. Когда вы переопределяете метод, вы не можете использовать аргумент, у которого есть дочерний класс исходного класса аргумента. Если вы добавите @Override в Z.pro c (Z p), ваш код не будет скомпилирован.
Давайте представим, что это возможно, тогда вы можете использовать какой-то метод из класса Z во время выполнения Z. pro c (Z p).
class Z extends Y {
public Z() {
v += 9;
}
public void proc(Z p) {
someActions();
System.out.println(39);
}
private void someActions() {
System.out.println("Some actions");
}
}
Теперь, когда вы выполняете
X x = new Z();
x.proc(new X());
Что должно произойти? В классе X нет метода someActions. Как это должно работать? Вот почему Z.pro c (Z p) не перекрывает X.pro c (X p). Класс Z имеет два разных метода: Z.pro c (Z p) и Y.pro c (X p).
При вызове
X x = new Z();
x.proc(new Z());
JVM выглядит для ближайшего переопределенного или оригинального метода с подписью «pro c (X)» к классу Z (поскольку класс X имеет метод «pro c (X)») находит его в классе Y и выполняет Y.pro c ( хр). Вот почему вы видите «57» на выходе.