Подтвердить что ты не робот

Супер ключевое слово в Java, интересное поведение, пожалуйста, объясните

Допустим, что у нас есть следующий код:

class A {

    public void doLogic() {
        System.out.println("doLogic from A");
    }
}

class B extends A {

    @Override
    public void doLogic() {
        System.out.println("doLogic from B");
    }

    public void doDifferentLogic() {
        System.out.println("doDifferentLogic from B");
        super.doLogic();
    }
}

class C extends B {

    @Override
    public void doLogic() {
        System.out.println("doLogic from C");
    }
}

public class Test {

    public static void main(String[] args) {
        C c = new C();
        c.doDifferentLogic();
    }
}

Когда мы выполняем этот код, ожидаемое поведение выглядит следующим образом: Так как c содержит ссылку на объект класса C, когда вы вызываете метод c.doDifferentLogic(), JVM ищет метод в классе C и, поскольку он не найден, он начинает искать дерево наследования. Как и ожидалось, метод doDifferentLogic() находится в суперклассе и выполняется. Однако ожидается, что конструкция super.doLogic() будет выглядеть из текущей ссылки "Точка зрения", которая имеет тип C. Таким образом, супер C должен быть B, но вместо этого вызывается метод из верхнего класса A.

Если вы удалите ключевое слово super или замените его на ключевое слово this (то же самое, что и "this" неявно), вы получите ожидаемое полиморфное поведение и вызывается doLogic() из класса C.

Итак, мой вопрос: Должен вызывать super.doLogic() be this.super.doLogic() (2) вместо static.super.doLogic() (1)?

Оба являются недопустимыми конструкциями, они здесь просто для того, чтобы лучше объяснить себя.

(1) или другими словами - из ссылки на текущий объект c, получить суперкласс текущего объекта и вызывать метод doLogic() вместо (2) из ​​этого класса получить суперкласс и вызвать его метод doLogic()?

4b9b3361

Ответ 1

В Java ключевое слово super всегда ссылается на суперкласс класса, в котором используется ключевое слово, а не на суперкласс динамического типа объекта, на который вызывается метод. Другими словами, super разрешается статически, а не динамически. Это означает, что в контексте класса B ключевое слово super всегда относится к классу A, независимо от того, выполняется ли метод B с использованием объекта C в качестве получателя. Насколько я знаю, нет способа динамически определять тип суперкласса и использовать его методы без использования отражения.

Надеюсь, это поможет!

Ответ 2

Здесь JLS определяет это специально:

  • Если форма супер. NonWildTypeArguments opt Идентификатор, тогда имя метода является Идентификатором, а класс, подлежащий поиску, является суперклассом класса, декларация которого содержит вызов метода.

Итак, Java рассматривает super как относящуюся к суперклассу класса, содержащего вызов super.method, а не к текущему типу времени выполнения.

Ответ 3

Всякий раз, когда выполняется super.doLogic() из класса B, он всегда будет ссылаться на метод doLogic() суперкласса класса B, который в этом случае будет classA. Это желаемое поведение, так что управление не будет проходить между классами внутри одного и того же метода. Это концепция контекста класса. Когда вы находитесь в контексте класса, вам нужно будет следовать правилам, установленным этим классом, и не продолжать передавать управление между различными контекстами.