如何在所有子构造函数中自动包含父方法的执行?

我有一个抽象类( Parent ),它有一个抽象方法( doSetup ),以及一个调用doSetup方法的成员方法。 我需要的是构造中的子类(实现Parent )应该自动调用doSetup方法,无论子类可能有多少构造函数。 是否有Java机制或设计模式可以帮助我解决这个问题?

 public abstract class Parent { abstract protected void sayHi(); protected void doSetup() { sayHi(); } } public class Child1 extends Parent { @Override protected void sayHi() { System.out.println("hi"); } public Child1() { // Construction needs to automatically include exec of doSetup() } public Child1(String string) { // Construction needs to automatically include exec of doSetup() System.out.println("another constructor"); } } 

这是实现常见构造代码的一种方法:

Parent.java

 public abstract class Parent { public Parent() { this("Default Value Goes Here"); } // Funneling everything through this main constructor. public Parent(String value) { this.doSetup(value); } // I've made this method private, as it shouldn't really // be accessed from sub classes, but if you require that, then // mark this method as protected & final instead. private void doSetup(String value) { System.out.println(value); } } 

Child.java

 public class Child extends Parent { // Deliberately not implementing constructors here, // but if I did, the first call would be to a super() // constructor to retain parent's construction functionality. } 

MainApp.java

 public class MainApp { public static void main(String[] args) { Child child = new Child(); } } 

运行上面的MainApp,您将看到默认值构造函数运行,它将输出“Default Value Goes Here”,因为它是由父级构造函数强制执行的。

一个好的IDE可能会警告不要在构造函数中使用可覆盖的方法。

可以通过以下代码certificate原因可能会产生令人惊讶的结果。

 class Base { Base() { init(); } protected void init() { } } class Child extends base { String a = "a"; String b; String c = "c"; String d; public Child() { // 1. Fields are nulled // 2. super() called // 2.1. init() called // 3. Field initialisations done (a, c) // 4. Rest of constructor: System.out.printf("EndConstr a: %s, b: %s, c: %s%n", a, b, c); } @Overridable protected void init() { System.out.printf("Init a: %s, b: %s, c: %s%n", a, b, c); c = "cc"; d = "dd"; } } 

控制行为的解决方案是提供一个最终的不​​可覆盖的方法,该方法以指定的方式调用可覆盖的受保护方法:

 class Base { public final void f() { X x = ...; onF(x); } protected /*abstract*/ void onF(X x) { } } class Child extends Base { @Overridable protected void onF(X x) { ... } } 

为什么不在父构造函数中包含doSetup() ? 为了避免从构造函数中调用可重写方法,您可以稍微改变一下模式:

 public abstract class Parent { final String greeting; public Parent(String greeting) { this.greeting = greeting; doSetup(); } final void doSetup() { System.out.println(greeting); } } 

然后,每个子类的构造函数都需要显式调用超级构造函数,例如:

 public class Child1 extends Parent { private static String default_greeting = "hi"; public Child1() { super(default_greeting); // prints "hi" } public Child1(String string) { super(string); // print a different greeting } } 

正如其他人所说,你不应该在超类的构造函数中调用一个可覆盖的方法。 这是为了避免this情况逃脱并最终产生难以调试的竞争条件,或者只是避免在从重写方法中访问尚未初始化的字段时抛出NullPointerException

现在,关于这个问题,如果你想为所有的构造函数运行公共代码,你需要的是一个初始化块

 public abstract class Parent { { // this is an initializer block that is inherited // by all subclasses and runs for every constructor // in the hierarchy this.doSetup(); } protected final void sayHi() { // final to avoid this to escape System.out.println("hi"); } protected final void doSetup() { // final to avoid this to escape sayHi(); } } public class Child1 extends Parent { public Child1() { // initilizer block automatically called } public Child1(String string) { // initilizer block automatically called System.out.println("another constructor"); } } 

运行此测试:

 new Child1(); new Child1("something"); 

产生以下输出:

 hi hi another constructor