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

Enforce super call on non constructor methods

是否可以强制重写方法来调用超类方法?构造函数总是需要调用它们的超类构造函数。但是我想在正常方法上强制执行此操作,而不考虑何时称为重要的位置。

示例:

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

}

不,这是不可能的。调用或不调用它覆盖的方法取决于覆盖方法。

不,那不可能。是否调用超类方法完全取决于覆盖方法。

但是,如果您想加强控制,有一种方法可以做到。

这叫做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!

不,这是不可能的。如果你允许一个方法被覆盖(通过不声明它或它的 class final)那么你无法控制覆盖它的方法的实现的大部分内容。但是,您可以记录 此类方法应调用超级class 的版本。您只能做很多事情来保护您的用户免受他们自己的伤害。

您可能还会发现其他设计更适合您。例如,如果你想允许 subclasses 覆盖计算的特定细节,而不是完全覆盖整个计算,那么你可以使用模板方法模式。在这种情况下,计算由一个 "template" 方法驱动,您可以根据需要声明 privatefinal,并且可自定义的细节在单独的非 finalpublicprotected,可能 abstract 驱动程序方法在适当的地方调用的方法。

是的,有可能,但有以下限制:

  • 该方法有一个非void return类型
  • 子classes(或子classes可访问的其他classes)不能创建return类型
  • 的实例

正如@Andreas 指出的那样,super 调用仍然可以通过 returning null 来避免。在实践中,这应该不是问题,但是在合约中强制执行非无效性(超级 class 文档)以及使用 a null-preventing annotation 是合理的,例如@Nonnull,因此任何现代 IDE 都可以在未调用超级 class 方法时给出编译错误。

例如:

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

虽然不严格 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,它就会在那一秒出现 link。