是否可以强制执行重写方法来调用超类方法?构造函数总是需要调用它们的超类构造函数。但是我希望在普通方法上强制执行此操作,而不是在它被称为问题时的位置。
示例:
public class A {
public void doSth() {
System.out.println("I must appear on console!");
}
}
public class B extends A {
@Override
public void doSth() {
System.out.println("Bla!"); // IDE should mark an error, because supermethod is not called.
}
}
答案 0 :(得分:9)
不,那是不可能的。完全取决于调用超类方法的重写方法。
但是,如果你想强制执行控制,有一种方法可以做到。
这称为Template Method Pattern。模板方法是抽象的还是存根(如此处所示)取决于它们是否必须执行某些操作,或者只是允许执行额外的操作。
public class A {
public final void doSth() { // final, preventing override by subclasses
beforeDoSth();
System.out.println("I must appear on console!");
afterDoSth();
}
protected void beforeDoSth() { // protected, since it should never be called directly
// Stub method, to be overridden by subclasses, if needed
}
protected void afterDoSth() {
// Stub method, to be overridden by subclasses, if needed
}
}
public class B extends A {
@Override
protected void afterDoSth() {
System.out.println("Bla!");
}
}
如果您执行new B().doSth()
,您将获得:
I must appear on console!
Bla!
答案 1 :(得分:2)
不,这是不可能的。如果你允许一个方法被覆盖(通过不声明它或它的类final
)那么你就无法控制有关覆盖它的方法的实现的任何内容。但是,您可以文档这些方法应该调用超类的版本。只有这么多,你可以做些什么来保护你的用户。
您可能还会发现有更适合您的替代设计。例如,如果要允许子类覆盖计算的特定细节,而不是完全覆盖整个计算,则可以使用模板方法模式。在这种情况下,计算由一个“模板”方法驱动,如果您愿意,可以声明private
或final
,并且可以在单独的非{{1}中实现可自定义的详细信息。 }},final
或public
,可能是protected
方法,驱动程序方法在适当的地方调用。
答案 2 :(得分:1)
不,这是不可能的。它取决于调用或不调用它覆盖的方法的重写方法。
答案 3 :(得分:1)
是的,考虑到以下限制,它是可能的:
void
返回类型正如@Andreas指出的那样,通过返回super
仍然可以避免null
来电。在实践中,这不应该是一个问题,但在合同(超类文档)中强制执行非空,并且使用a null-preventing annotation,例如,这是合理的。 @Nonnull
,以便任何现代IDE在未调用超类方法时都会产生编译错误。
例如:
import javax.annotation.Nonnull;
public class A {
public static final class Result {
private Result() {
// declare constructor private so the class cannot be
// instantiated from outside
}
}
/**
* Does something.
*
* @return the result; never {@code null}
*/
public @Nonnull Result doSth() {
System.out.println("I must appear on console!");
return new Result();
}
}
//...
public class B extends A {
@Override
public @Nonnull Result doSth() {
System.out.println("Bla!");
// only way to get a Result instance is through super.doSth()
Result res = super.doSth();
/* manipulate the result as needed */
return res;
}
}
答案 4 :(得分:1)
虽然不是严格的Java相关,但我正在寻找这个问题的答案,因为它与Android有关,并在支持注释库中找到了名为“@CallSuper”的注释。它完全符合您的想法,如果子类不调用super的@CallSuper注释方法实现,则抛出一个lint错误。
这解决了我的用例,但同样,我知道该解决方案严格依赖于Android。如果距离太远,请告诉我,我会删除答案。
以下是有关@CallSuper的更多文档。 https://developer.android.com/reference/android/support/annotation/CallSuper.html https://developer.android.com/studio/write/annotations.html(只需搜索CallSuper,它就会显示在第二个链接中。