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