Java,隐式调用重写的方法

Java,隐式调用重写的方法,java,inheritance,oop,Java,Inheritance,Oop,现在,在一些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(),然后向上遍历每个父类,运行重写

现在,在一些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()

所以
A
的构造函数实际上是

A() {
  //init some state in a
  f(); //run f(), which will depend on the previous operation
}
如果我做了类似于
newc()的事情
我想调用
C.f()
,然后调用
B.f()
,然后调用
A.f()


无论如何,如果有更聪明的方法,我愿意接受。

据我所知,没有办法做到这一点。AspectJ可能会做类似的事情,但是我想,您必须用注释来标记它,这几乎比调用
super.f()
要简单得多。您需要表明正在调用超类方法,因为您需要能够分别为每个子类做出决定-否则,您可能有一个子类根本不想将任何内容委托给超类-因此默认情况下,您只需输入代码。

在构造函数中调用非final方法通常是一个坏主意-至少,我建议您大量记录它。请记住,当调用f()时,不会调用C的构造函数,也不会调用任何变量初始值设定项。对象只初始化了一半,因此需要非常小心地编写方法

但是在普通Java中,无法隐式调用
super.f()
。考虑到我将在代码中提出的大量警告,只有一条语句远远不是世界末日:)


如果您想验证它是否被调用,您可以在调用后立即在A的构造函数中检查
A.f()
的结果-这将检查调用是否已达到顶层。

这可能会对您有所帮助-这是一种强制子类调用super的方法;这将帮助您检测开发人员错误,其中子类的实现者忘记继续调用super.f()


因此,子级重写doF(),但需要调用super.doF()

+1表示“在构造函数中调用非final方法通常是个坏主意”(根据经验:-)我不需要运行任何构造函数,只要执行()的第一部分,我们就处于良好状态。这是通过使用私有名称空间在不使用序列化接口的情况下进行序列化的黑客攻击的一部分。基本上所有类都声明了它们将要预先使用的变量,但init是私有名称空间。谢谢你的回复,Jon,我觉得这是不可能的,很高兴有第二个意见,有时候在构造函数中使用模板方法模式很有吸引力。只要抽象(或非最终)方法在不依赖于状态的情况下实现算法,它就会工作。另一种解决方案是使用延迟初始化。我有一个关于这个问题的博客:
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();
 }
}