В Java можно ли вызвать общедоступный переопределенный метод из другого класса?

#java #polymorphism #overriding #super #visitor-pattern

#java #полиморфизм #переопределение #супер #посетитель-шаблон

Вопрос:

Обычно переопределенный метод может быть вызван с помощью super. Например:

 public class SuperClass {
   public void something() {
      out("called from super");
   }
}

public class SubClass extends SuperClass {
   @Override
   public void something() {
      out("called from sub");
      super.something(); // This is fine
   }

   public static void main(String[] args) {
      new SubClass().something(); // Calls both methods
   }
}
  

Но я хочу вызвать метод super.something() из другого класса:

 public class SubClass2 extends SuperClass {
   @Override
   public void something() {
      out("called from sub2");
      new DecidingClass().maybeCallSuperSomething(this);
   }

   public static void main(String[] args) {
      new SubClass2().something();
   }
}

public class DecidingClass {
   public void maybeCallSuperSomething(SuperClass visitor) {
      boolean keepGoing = true;
      // Do some work, maybe set keepGoing to false
      // ...
      if (keepGoing) {
         // How do I call the Overridden method?
         visitor.something() // Causes recursive loop
         // visitor.super.something() ????
      }
   }
}
  

Возможно ли это? У меня есть обходной путь, но он немного неаккуратный.

Ответ №1:

Короткий ответ, нет.

Реализация суперкласса видна только прямым подклассам. Внешние классы в любом случае не должны знать о функциональности отдельных реализаций метода; сцепление = плохое.

Вероятно, вам нужно пересмотреть свой дизайн, если это необходимо.

Комментарии:

1. 1 Эта идея отражена в LSP: en.wikipedia.org/wiki/Liskov_substitution_principle

2. Жаль, я подумал, что это может привести к быстрому решению, следует ли вызывать метод или нет. Обходной путь достаточно прост, для этого просто требуется вызвать суперметод внутри подметода, т.Е. if (new DecidingClass().decide(this)) { super.something(); }

Ответ №2:

Вы не можете вызвать метод super — это часть спецификации Java, но вот (уродливый) вариант:

 public class SuperClass {

    public void something(boolean invokeSuper) {
        // do something
    }
}

public class SubClass extends SuperClass {

    public void something(boolean invokeSuper) {
        if (invokeSuper) {
            super.something();
        } else {
            // do something
        } 
    }
}
  

Ответ №3:

Это немного очевидно, но… обычный способ справиться с этим — извлечь тело метода базового класса в отдельный метод, чтобы его можно было вызвать напрямую. Возможно, вы захотите, чтобы он был окончательным, как для повышения производительности, так и для того, чтобы подчеркнуть, что его нельзя переопределять.

 public class SuperClass {
   public void something() {
      doSomething();
   }
   public final void doSomething() {
      out("called from super");
   }

}

public class DecidingClass {
   public void maybeCallSuperSomething(SuperClass visitor) {
      // ...
         visitor.doSomething();
      // ...
   }
}