Java, вызов переопределенного метода неявно

Прямо сейчас в каком-то Java-коде у меня есть что-то вроде этого

class A {
 void f() {

 }
 A() {
  f();
 }
}

class B extends A{
 @Override
 void f() {
  //do some stuff
  super.f();
 }
}

class C extends B {
 @Override
 void f() {
  //do some stuff
  super.f();
 }
}

Я хочу, чтобы f() вызывал, а затем итерацию вверх через каждый родительский класс, запуская переопределенный f(). Я делаю это, явно называя super.f(), хотя я бы не хотел этого делать.

Причина, по которой я делаю это, - это пост-обработка, которая должна быть выполнена после достижения конструктора в A. И в каждом классе есть состояние, которое должно быть правильно init'd, поэтому у нас есть восходящий след f().

Итак, конструктор A действительно

A() {
  //init some state in a
  f(); //run f(), which will depend on the previous operation
}

Если я делаю что-то вроде new C();, я хочу вызвать C.f(), затем B.f(), затем A.f(), называемый

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

Ответ 1

Вызов не конечных методов в конструкторе - это, как правило, плохая идея - по крайней мере, я предлагаю вам документировать ее в значительной степени. Имейте в виду, что, когда вызывается f(), конструктор C не будет вызван - и ни один из переменных инициализаторов не будет. Объект только частично инициализирован, поэтому методы нужно будет писать очень осторожно.

Нет никакого способа неявного вызова super.f(), хотя в обычной Java. Учитывая большие предупреждения, которые я буду использовать для этого кода, одно утверждение далеко от конца света:)

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

Ответ 2

Это может помочь вам несколько - это способ обеспечить, чтобы класс child вызывал супер; это поможет вам обнаружить ошибки разработчиков, когда разработчик дочернего класса забыл продолжить вызов цепочки на super.f():

class A {
 boolean fDone;

 public final void f() {
  fDone = false;
  doF();
  if (!fDone) {
   throw new IllegalStateException("super.f() was not called");
  }
 }

 protected void doF() {
  //do some operation
  fDone = true;
 }
}

class B extends A {
 protected void doF() {
  //some operation, maybe repeat this pattern of using a flag to enforce super call
  super.doF();
 }
}

Итак, ребенок переопределяет doF(), но требуется вызвать super.doF();

Ответ 3

Насколько я знаю, нет никакого способа сделать это. AspectJ может сделать что-то похожее на это, но тогда вам придется пометить его аннотацией, я полагаю, что вряд ли будет работать, чем просто позвонить super.f(). Вам нужно указать, что метод суперкласса вызывается, потому что вам нужно иметь возможность принимать это решение для каждого подкласса отдельно - иначе у вас может быть подкласс, который вообще не хочет делегировать что-либо суперклассу, поэтому по умолчанию вы просто вставляете код.