简体   繁体   English

需要覆盖方法来调用 super

[英]Require override of method to call super

I want that when a child class overrides a method in a parent class, the super.method() is called in that child method.我希望当子类覆盖父类中的方法时,在该子方法中调用super.method()

Is there any way to check this at compile time?有没有办法在编译时检查这个?
If not, how would I go about throwing a runtime exception when this happens?如果没有,发生这种情况时我将如何抛出运行时异常?

There's no way to require this directly.没有办法直接要求这个。 What you can do, however, is something like:但是,您可以做的是:

public class MySuperclass {
    public final void myExposedInterface() {
        //do the things you always want to have happen here

        overridableInterface();
    }

    protected void overridableInterface() {
        //superclass implemention does nothing
    }
}

public class MySubclass extends MySuperclass {
    @Override
    protected void overridableInterface() {
        System.out.println("Subclass-specific code goes here");
    }
}

This provides an internal interface-point that subclasses can use to add custom behavior to the public myExposedInterface() method, while ensuring that the superclass behavior is always executed no matter what the subclass does.这提供了一个内部接口点,子类可以使用它向公共myExposedInterface()方法添加自定义行为,同时确保无论子类做什么都始终执行超类行为。

solution:解决方案:

Look at the findBugs project ...看看 findBugs 项目...

Example ...例子 ...

    import javax.annotation.OverridingMethodsMustInvokeSuper;
       :

    @OverridingMethodsMustInvokeSuper
    protected String getLabel(){
       ... 
    }

Override:覆盖:

    @Override
    protected String getLabel(){
       // no call to Super Class!!
       // gives a message 
       ... 
    }

I've been using it for about 3 years.我已经使用它大约 3 年了。 No kittens have been harmed.没有小猫受到伤害。

Well, I can presume that the initialization in the superclass method is used elsewhere.好吧,我可以假设超类方法中的初始化在其他地方使用。 I would set a flag in the superclass method and check it later when the initialization is needed.我会在超类方法中设置一个标志,稍后在需要初始化时检查它。 More specifically, let's say setupPaint() is superclass method that needs always to be called.更具体地说,假设 setupPaint() 是需要始终调用的超类方法。 so then we can do:那么我们可以这样做:

class C {
  private boolean paintSetupDone = false;

  void setupPaint() { 
    paintSetupDone = true;
    ...
  }

  void paint() { // requires that setupPaint() of C has been called
     if (!paintSetupDone) throw RuntimeException("setup not done");
     ...
  }
}

Now if a subclass of C doesn't call the setupPaint() function, there's no way that the (private) flag will be set, and methods requiring the contractual call to the superclass setupPaint(), such as paint() will be able to check and throw that exception.现在,如果 C 的子类不调用 setupPaint() 函数,则无法设置(私有)标志,并且需要对超类 setupPaint() 进行契约调用的方法,例如paint() 将能够检查并抛出该异常。

As noted elsewhere, there is by the way no way of requiring such a contract in java.正如其他地方所指出的,顺便说一下,java 中没有办法要求这样的合同。

How about if you make the call yourself?如果你自己打电话呢? Instead of dictating implementation to a subclass (which you really can't do) just enforce it with the interface and implementation of your baseclass.与其将实现指定给子类(您确实无法做到),只需使用基类的接口和实现来强制执行即可。

public abstract class BaseClass {

    public final void callMeFirst() {
        // method that needs to be called before subclassing method runs
    }

    public final void makeSureWhateverGetsCalled() {
        callMeFirst();
        overrideMe();
    }

    public abstract void overrideMe();
}

public class OverridingClass extends BaseClass {
    @Override
    public void overrideMe() {
        // do whatever needs to be done AFTER callMeFirst() is run
    }
}

unfortunately, there's no way to require it at compile time, and no way to detect it at runtime (unless there is some app specific logic or sequence of events that you could use to detect the method not being called).不幸的是,没有办法在编译时要求它,也没有办法在运行时检测到它(除非有一些特定于应用程序的逻辑或事件序列可以用来检测未被调用的方法)。 best thing to do is heavily document the method.最好的办法是大量记录该方法。

if you really, really want to go down this path, you could use something like this pattern:如果你真的,真的想走这条路,你可以使用这样的模式:

public class BaseClass {

  public final void myMethod() {
    // do special stuff here which must always happen ...

    // allow subclasses to customize myMethod() here
    myMethodCustom();
  }

  protected void myMethodCustom() {
    // base class does nothing
  }
}

There's not a way to check for this at compile time.没有办法在编译时检查这一点。 (However, I've heard suggestions that you could do this at compile time with annotations, although I've never seen a specific annotation solution and I don't know how it would be done.) For a way to throw an exception at run time, see this thread . (但是,我听说您可以在编译时使用注释执行此操作的建议,尽管我从未见过特定的注释解决方案,我不知道如何完成。)运行时,请参阅此线程 Perhaps you can refactor your code so that the base class has a final method that includes the essential parts and calls a non-final method that does not require a super call.也许你可以重构你的代码,让基类有一个包含基本部分的final方法,并调用一个不需要super调用的非 final 方法。

For the Android Developers out there, you can simply use the @CallSuper annotation.对于那里的Android开发人员,您可以简单地使用@CallSuper注释。

Sample:样本:

public class BaseClass {
  @CallSuper
  public void myMethod() {
    //do base required thing
  }
}

On the overriding class:在覆盖类上:

public class OverridingClass extends BaseClass{

    @Override
    public void myMethod(){
        super.myMethod(); //won't compile if super is not called
        //do overring thing here
    }
}

AndroidX Solution:安卓X解决方案:

Require super that throws compile error if not called in @Override method:如果在@Override方法中未调用,则需要super抛出编译错误:

import androidx.annotation.CallSuper;

class BaseClassThatRequiresSuper {
    
    @CallSuper
    public void requireSuper() {
        
    }
}

class ChildClass extends BaseClassThatRequiresSuper {
    
    @Override
    public void requireSuper() {
        super.requireSuper();
    }
}

If ChildClass does not call super.requireSuper() it will give you a compile error.如果ChildClass没有调用super.requireSuper()它会给你一个编译错误。 Saying :说:

Overriding method should call super.requireSuper

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM