【发布时间】:2011-07-28 02:58:15
【问题描述】:
我希望当子类覆盖父类中的方法时,在该子方法中调用super.method()。
有没有办法在编译时检查这个?
如果没有,发生这种情况时我将如何抛出运行时异常?
【问题讨论】:
我希望当子类覆盖父类中的方法时,在该子方法中调用super.method()。
有没有办法在编译时检查这个?
如果没有,发生这种情况时我将如何抛出运行时异常?
【问题讨论】:
没有办法直接要求这个。但是,您可以做的是:
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() 方法添加自定义行为,同时确保无论子类做什么,都始终执行超类行为。
【讨论】:
看看 findBugs 项目...
示例 ...
import javax.annotation.OverridingMethodsMustInvokeSuper;
:
@OverridingMethodsMustInvokeSuper
protected String getLabel(){
...
}
覆盖:
@Override
protected String getLabel(){
// no call to Super Class!!
// gives a message
...
}
我已经使用它大约 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 中没有办法要求这样的合同。
【讨论】:
如果你自己打电话怎么样?与其指定子类的实现(你真的做不到),不如用你的基类的接口和实现来强制它。
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 修饰符以确保不会发生这种情况。
不幸的是,没有办法在编译时要求它,也没有办法在运行时检测它(除非有一些特定于应用程序的逻辑或事件序列可用于检测未调用的方法)。最好的办法是大量记录方法。
如果你真的,真的想走这条路,你可以使用类似这样的模式:
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
}
}
【讨论】:
没有办法在编译时检查这一点。 (但是,我听说你可以在编译时使用注释来执行此操作,尽管我从未见过特定的注释解决方案,也不知道如何完成。)运行时间,请参阅this thread。也许您可以重构您的代码,使基类具有包含基本部分的final 方法并调用不需要super 调用的非最终方法。
【讨论】:
对于 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
}
}
【讨论】:
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
【讨论】: