对非构造函数方法强制执行超级调用

时间:2016-02-05 18:39:20

标签: java inheritance superclass

是否可以强制执行重写方法来调用超类方法?构造函数总是需要调用它们的超类构造函数。但是我希望在普通方法上强制执行此操作,而不是在它被称为问题时的位置。

示例:

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

}

5 个答案:

答案 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)那么你就无法控制有关覆盖它的方法的实现的任何内容。但是,您可以文档这些方法应该调用超类的版本。只有这么多,你可以做些什么来保护你的用户。

您可能还会发现有更适合您的替代设计。例如,如果要允许子类覆盖计算的特定细节,而不是完全覆盖整个计算,则可以使用模板方法模式。在这种情况下,计算由一个“模板”方法驱动,如果您愿意,可以声明privatefinal,并且可以在单独的非{{1}中实现可自定义的详细信息。 }},finalpublic,可能是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,它就会显示在第二个链接中。