对非构造函数方法执行超级调用
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" 方法驱动,您可以根据需要声明 private
或 final
,并且可自定义的细节在单独的非 final
、public
或 protected
,可能 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。
是否可以强制重写方法来调用超类方法?构造函数总是需要调用它们的超类构造函数。但是我想在正常方法上强制执行此操作,而不考虑何时称为重要的位置。
示例:
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" 方法驱动,您可以根据需要声明 private
或 final
,并且可自定义的细节在单独的非 final
、public
或 protected
,可能 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。