Java,隐式调用重写方法

时间:2009-10-02 21:16:05

标签: 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(),然后向上遍历每个父类,运行被覆盖的f()。我通过明确地调用super.f()来做到这一点,尽管我不想这样做。

我这样做的原因是必须在到达A中的构造函数之后进行后处理。并且每个班级都有适当的初始状态,这就是为什么我们有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()

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

3 个答案:

答案 0 :(得分:8)

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

虽然在普通的Java中没有办法隐式调用super.f()。鉴于我将围绕该代码发出大量警告,单一陈述远非世界末日:)

如果你想验证它是否被调用,你可以随时在A的构造函数中检查A.f()的结果,这将检查该调用是否已达到顶级。

答案 1 :(得分:4)

这可能对你有所帮助 - 这是一种强制子类调用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();

答案 2 :(得分:1)

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