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 достигнут. И в каждом классе есть состояние, которое должно быть надлежащим образом инициировано, поэтому у нас есть восходящий след f()"S.

Так что конструктор 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() называется

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

3 ответа

Решение

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

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

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

Это может вам чем-то помочь - это способ обеспечить, чтобы дочерний класс вызывал super; это поможет вам обнаружить ошибки разработчика, когда разработчик дочернего класса забыл продолжить вызов по цепочке 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();

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

Другие вопросы по тегам