【问题标题】:Require override of method to call super需要重写方法来调用 super
【发布时间】:2011-07-28 02:58:15
【问题描述】:

我希望当子类覆盖父类中的方法时,在该子方法中调用super.method()

有没有办法在编译时检查这个?
如果没有,发生这种情况时我将如何抛出运行时异常?

【问题讨论】:

标签: java super


【解决方案1】:

没有办法直接要求这个。但是,您可以做的是:

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");
    }
}

这提供了一个内部接口点,子类可以使用它向公共myExposedInterface() 方法添加自定义行为,同时确保无论子类做什么,都始终执行超类行为。

【讨论】:

  • +1 .. 更好的是,在基类中将 overridableInterface() 标记为抽象。
  • 哈,实际上我在阅读这篇文章之前就这样做了,这是基于我最终发现的另一篇文章的建议。不过还是谢谢!如果可以的话,我会投票。
  • 在 FindBugs 中有一个注释 - 见下文:Find bugs -- @OverridingMethodsMustInvokeSuper。而且效果很好。
【解决方案2】:

解决方案:

看看 findBugs 项目...

示例 ...

    import javax.annotation.OverridingMethodsMustInvokeSuper;
       :

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

覆盖:

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

我已经使用它大约 3 年了。没有小猫受到伤害。

【讨论】:

    【解决方案3】:

    好吧,我可以假设在其他地方使用了超类方法中的初始化。我会在超类方法中设置一个标志,稍后在需要初始化时检查它。更具体地说,假设 setupPaint() 是需要始终调用的超类方法。那么我们可以这样做:

    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");
         ...
      }
    }
    

    现在,如果 C 的子类不调用 setupPaint() 函数,则无法设置 (private) 标志,以及需要对超类 setupPaint() 进行合同调用的方法,例如 paint()将能够检查并抛出该异常。

    正如其他地方所指出的,在 java 中没有办法要求这样的合同。

    【讨论】:

      【解决方案4】:

      如果你自己打电话怎么样?与其指定子类的实现(你真的做不到),不如用你的基类的接口和实现来强制它。

      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
          }
      }
      

      【讨论】:

      • 这不会阻止孩子覆盖makeSureWhateverGetsCalled() 并且,嗯,不调用东西。此模式的其他答案添加了 final 修饰符以确保不会发生这种情况。
      • 顺便说一下,我相信这是模板方法设计模式的一个例子。
      【解决方案5】:

      不幸的是,没有办法在编译时要求它,也没有办法在运行时检测它(除非有一些特定于应用程序的逻辑或事件序列可用于检测未调用的方法)。最好的办法是大量记录方法。

      如果你真的,真的想走这条路,你可以使用类似这样的模式:

      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
        }
      }
      

      【讨论】:

        【解决方案6】:

        没有办法在编译时检查这一点。 (但是,我听说你可以在编译时使用注释来执行此操作,尽管我从未见过特定的注释解决方案,也不知道如何完成。)运行时间,请参阅this thread。也许您可以重构您的代码,使基类具有包含基本部分的final 方法并调用不需要super 调用的非最终方法。

        【讨论】:

          【解决方案7】:

          对于 Android 开发人员,您可以简单地使用 @CallSuper 注释。

          示例:

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

          在覆盖类上:

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

          【讨论】:

            【解决方案8】:

            AndroidX 解决方案:

            如果没有在@Override 方法中调用,则需要super 引发编译错误:

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

            如果ChildClass 没有调用super.requireSuper(),它会给你一个编译错误。说:

            Overriding method should call super.requireSuper

            【讨论】:

              猜你喜欢
              • 2023-01-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2023-04-04
              • 1970-01-01
              相关资源
              最近更新 更多