Метод суперкласса должен ссылаться на другой (хотя и переопределенный) метод

1

Имея следующий суперкласс:

public class SuperClass {

    protected Integer a;
    protected Integer b;

    public void doSomething() {
        this.a = 10;
    }

    public void doEverything() {
        SuperClass.this.doSomething();
        this.b = 20;
    }

    public static void main(String[] args) {
        SuperClass instance = new SubClass();
        instance.doEverything();
        System.out.println(instance.a); //should print 10
        System.out.println(instance.b);
    }
}

И следующий подкласс:

public class SubClass extends SuperClass {

    @Override
    public void doSomething() {
        super.doSomething();
        super.a *= 10;
    }

    public void doEverything() {
        super.doEverything();
        this.b += 5;
    }
}

Выходы:

100

25

Итак, SuperClass.this.doSomething(); является доступ к SubClass doSomething, но мне нужно, чтобы получить доступ к SuperClass doSomething. В этом случае у меня нет ключевого слова super, потому что я уже супер!

  1. Есть ли способ SuperClass.this.doSomething на глубокий SuperClass.this.doSomething, поэтому он будет выводить 10 для первого выходного значения?

    ¹ Меня интересуют ссылки: мы могли бы, конечно же, извлечь SuperClass doSomething в личный метод auxiliar и получить к нему доступ напрямую.

  2. Если нет способа, то может ли ситуация, когда метод суперкласса для доступа к другому (хотя и переопределенному) методу означает, что мой проект ООП неверен? Зачем?

  • 0
    возможный дубликат того, как вызвать переопределенный метод суперкласса
  • 0
    @fabian Размышляя об ООП, разве суперкласс не должен иметь доступ к своему (хотя и переопределенному) методу? - Я думаю, что на этот вопрос не было ответа: я видел этот ответ, когда писал свой вопрос, но он не достиг этого момента.
Показать ещё 9 комментариев
Теги:
oop
inheritance
override
method-overriding

4 ответа

3
Лучший ответ

Я предполагаю, что вы пришли на Java с фона C++. Языки похожи в понятиях и синтаксисе, но они различны в реализации.

Вы можете достичь того, что, на ваш взгляд, тоже есть на Java, но структура будет выглядеть иначе, чем C++.

В Java конструкция SuperClass.this в вашем примере точно такая же, как и this, поэтому SuperClass.this.doSomething(); это именно то, что может сделать doSomething(). Итак, почему Java вообще имеет конструкцию SuperClass.this? Он имеет значение, не связанное с наследованием. Это полезно в контексте вложенных классов.

Представьте себе такую структуру:

class A {
    class B {
        public void doSomething() {
         // this here refers to an instance of the class B
         System.out.println(this);
         // We need to write is this way,
         // because this hides the this reference to the instance of A.
         // A.this is the instance of A where this is nested
         System.out.println(A.this); 
     }
}

Итак, как вы можете быть уверены, что сможете иметь метод в классе, который подклассы могут переопределять и все еще иметь возможность вызвать конкретную реализацию?

Ну, в строгом смысле, вы не можете. То, что вы можете сделать, - это создать final метод, который нельзя переопределить, и вызывать его из неконфигурированного метода.

class SuperClass {
    public void doSomething() {
        doSuperClassyThing();
    }

    public final void doSuperClassyThing() { // cannot be overridden
        ...
    }
}

Аналогичный подход (с немного другой целью) вы можете увидеть в шаблоне метода шаблона.

  • 0
    Хороший ответ. Спасибо, что пришли с подходом внутреннего класса.
  • 0
    Хотя это был самый информативный ответ на данный момент, я принимаю его =] Кстати, я только что открыл новые возможности после прочтения, которое я имел здесь. Спасибо!
2

Вы не можете делать то, что хотите. Способ полиморфизма работает, делая то, что вы видите.

Это означает, что нет прямого способа вызвать SuperClass.doSomething() из SuperClass.doSomething(), не перейдя в SubClass.doSomething(), если вы не работаете с фактическим экземпляром SuperClass.

На некоторых других языках вы можете рассказать, как обрабатывать это, например, с помощью ключевого слова virtual в c++, но в java у вас нет этой опции. Все методы динамически привязаны, поэтому вы не можете этого сделать. Вы не можете переопределить или вообще не переопределить его.

  • 0
    Если нет пути, думая об ООП, разве суперкласс не должен иметь доступ к своему собственному (хотя и переопределенному) методу?
  • 1
    @falsarella добавлен в ответ.
Показать ещё 1 комментарий
2

Ответ заключается в том, что вы не можете ссылаться на него. Единственный способ сделать это - это подход частного вспомогательного метода, о котором вы уже знаете.

Если вы хотите узнать причину, почему, я думаю, это просто потому, что это затруднит язык без причины; вы всегда можете получить тот же результат с помощью частного вспомогательного метода. Синтаксис SuperClass.this.doSomething() уже сделан для чего-то другого. Это означает вызов метода doSomething на охватывающем экземпляре, если SuperClass является закрывающим классом.

  • 0
    Если нет пути, думая об ООП, разве суперкласс не должен иметь доступ к своему собственному (хотя и переопределенному) методу?
  • 0
    @falsarella Ответ отредактирован.
Показать ещё 1 комментарий
1

Если вы когда-нибудь окажетесь в этой ситуации, возможно, вам следует переосмыслить и подумать, что структура классов еще не верна.

Попробуйте реализовать один из следующих подходов:

  1. Состав над наследством.
  2. Создание нового уровня Inheritance (класс в середине, который имеет ссылку на super).
  3. То же, что и (2.), но с использованием внутреннего класса.
  4. Извлеките разыскиваемый метод в отдельный закрытый и вызовите его там, где это применимо.

Поскольку (1.) не было бы таким же сухим, как другие, (4.) оставляет ощущение обходного пути, и (2.) потребует создания нового файла и будет ссылаться на внешний SuperClass; Я думаю, что самым близким подходом было бы (3.), что является единственным решением, которое каким-то образом ссылается на super в SuperClass (хотя на самом деле оно ссылается на внутренний класс SuperClass):

SuperClass.java:

public abstract class SuperClass {

    protected Integer a;
    protected Integer b;

    public void doSomething() {
        this.a = 10;
    }

    public abstract void doEverything();

    public static class Impl extends SuperClass {

        @Override
        public void doEverything() {
            super.doSomething();
            this.b = 20;
        }
    }

    public static void main(String[] args) {
        SuperClass instance = new SubClass();
        instance.doEverything();
        System.out.println(instance.a); //prints 10
        System.out.println(instance.b);
    }
}

SubClass.java:

public class SubClass extends SuperClass.Impl {

    @Override
    public void doSomething() {
        super.doSomething();
        super.a *= 10;
    }

    @Override
    public void doEverything() {
        super.doEverything();
        this.b += 5;
    }
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню