Почему строка, помеченная // 1, печатает 57 вместо 39? - PullRequest
0 голосов
/ 17 февраля 2020
class X {
    protected int v = 0;

    public X() {
        v += 10;
    }

    public void proc(X p) {
        System.out.println(43);
    }
}

class Y extends X {
    public Y() {
        v += 5;
    }

    public void proc(X p) {
        System.out.println(57);
    }

    public int getV() {
        return v;
    }
}

class Z extends Y {
    public Z() {
        v += 9;
    }

    public void proc(Z p) {
        System.out.println(39);
    }
}

class Main {
    public static void main(String[] args) {
        X x = new Z();
        Y y = new Z();
        Z z = new Z();
        x.proc(z);// 1
        System.out.println(y.getV());
    }
}

Из того, что я могу понять, метод pro c () вызывается для объекта типа X, который "содержит" тип Z, а во время выполнения JVM проверяет тип объекта и переопределяет метод с помощью pro. c () метод из Y. Но параметр метода имеет тип Z, почему он не вызывает перегруженный метод из класса Z?

Ответы [ 4 ]

1 голос
/ 17 февраля 2020

Это происходит потому, что вы не переопределяете метод '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» на выходе.

0 голосов
/ 17 февраля 2020

Просто чтобы уточнить ответ Федерико. Фактически, объект «x» - это переменная «X», которая указывает на экземпляр «Z» в памяти. Экземпляр "Z" имеет только два метода:

void proc(Z p)
void proc(X p)

Но среда выполнения знает только о втором методе, реализованном в классе "X", и переопределяется методом, реализованным в классе "Y". Итак, когда вы вызываете:

x.proc(z)

Среда выполнения знает только об этом втором методе и вызывает его, выполняя переопределенный метод.

0 голосов
/ 17 февраля 2020

Поскольку Y является ближайшим к Z в иерархии, вы всегда получите 57, передав экземпляр Z, на который ссылается Y или выше в иерархии, в переопределенную proc, например:

class Main {
    public static void main(String[] args) {
        X x = new Z();
        Y y = new Z();
        Z z = new Z();
        x.proc(z);
        y.proc(z);
        z.proc(z);

        x.proc(y);
        y.proc(y);
        z.proc(y);

        x.proc(x);
        y.proc(x);
        z.proc(x);
    }
}

Выход:

57
57
39
57
57
57
57
57
57

Как видно из вывода, единственный раз, когда вы получаете 39, это когда вы звоните proc на ссылка Z.

0 голосов
/ 17 февраля 2020

Поскольку вы передаете X в proc, поэтому proc для класса Y превалирует.

Если вы передали фактический Z, объявленный как Z, это напечатало бы 39.

Z x = new Z();
X y = new Z();
Z z = new Z();


z.proc(x); // prints 39
z.proc(y); // prints 57
...