开发者

Require override of method to call super

开发者 https://www.devze.com 2023-03-23 05:32 出处:网络
I w开发者_如何学Goant that when a child class overrides a method in a parent class, the super.method() is called in that child method.

I w开发者_如何学Goant that when a child class overrides a method in a parent class, the super.method() is called in that child 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.


solution:

Look at the findBugs project ...

  • FindBugs
    • Annotations package

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

As noted elsewhere, there is by the way no way of requiring such a contract in 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
    }
}


For the Android Developers out there, you can simply use the @CallSuper annotation.

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


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.


AndroidX Solution:

Require super that throws compile error if not called in @Override method:

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. Saying :

Overriding method should call super.requireSuper

0

精彩评论

暂无评论...
验证码 换一张
取 消