如何在此(…)或超级(…)之前“插入”代码?

有没有办法在调用super(...)this(...)构造函数之前实现初步计算? 请考虑以下示例:

 public class Test { private final int n; private final int m; private final int[] store; public Test(int n, int m) { /* This is common (most generic) constructor of the class Test. It is desirable to invoke it via this(...) call from any other constructor of this class since it contains some common initialization tasks, which are better to concentrate in one place instead of scattering them throught the class, due to maintainability and security reasons. */ this.n = n; this.m = m; store = new int[n]; // ... } public Test(Object data) { /* This is specific constructor. It depends on some parameters which must be processed prior to a call of the Test(int n, int m) constructor to get its arguments. The problem is, this processing cannot appear here because a call to this(...) must be the first statement in a constructor. */ int a; // Must be calculated via lengthy code int b; // Must be calculated via lengthy code this(a, b); // <- Compiler error here // ... further initialization } } 

如何实现参数计算? 最简单的解决方案是用静态方法替换特定的构造函数。 但是,如果它必须是一个构造函数而没有别的东西(例如,它有可能在后代类中使用)。 到目前为止,我发现的最佳解决方案是引入一个静态内部类,其中包含公共构造函数的所有参数,并使用它来存储特定构造函数开头的参数:

 public class Test { private final int n; private final int m; private final int[] store; protected static class ConstrParams { int nParam; int mParam; ConstrParams(int n, int m) { nParam = n; mParam = m; } } protected Test(ConstrParams params) { /* This is the common constructor now. It is marked as protected because it is essentially auxiliary, as well as the class ConstrParams is. */ n = params.nParam; m = params.mParam; store = new int[n]; // ... } public Test(int n, int m) { // This is public interface to the common constructor. this(new ConstrParams(n, m)); } private static ConstrParams makeParams(Object data) { /* This is a procedure that inserts lengthy calculations before constructor chain invocation. */ int a = 0; // Calculate a from data int b = 0; // Calculate b from data return new ConstrParams(a, b); } public Test(Object data) { // Specific constructor. Now compiles successfully. this(makeParams(data)); // ... further initialization } } 

有没有更好的解决方法? Test(Object data)必须调用一些super(...)构造函数而不是this(...)情况更糟,因为在这种情况下我们灵活性较低,并且通常无法更改祖先类的代码。

您还可以创建辅助方法来计算ab并在this(...)表达式中调用它们。 例如:

 public Test(Object data) { this(computeA(data), computeB(data)); } private static int computeA(Object data) { ... } private static int computeB(Object data) { ... } 

此解决方案适用于Java 8及更高版本。 我会创建另一个接受Supplier构造函数。 方法Supplier::get()返回值:

 public Test(Supplier n, Supplier m) { this.n = n.get(); this.m = m.get(); store = new int[n.get()]; } 

可能以这种方式使用:

 public Test(Object data) { this(() -> { int a = data.hashCode(); // expensive calculation return a; }, () -> { int b = data.hashCode(); // expensive calculation return b; }); } 

这种方法将简化另一个构造函数,只留下一个负责封装的主要构造函数:

 public Test(int n, int m) { this(() -> n, () -> m); } 

这是我发现的一种通用方法。 它允许在调用this(...)super(...)之前注入任何代码,从而克服Java this(...)super(...)的限制,成为第一个语句。构造函数。

 public class Test { private final int n; private final int m; private final int[] store; public Test(int n, int m) { // Primary constructor is unchanged this.n = n; this.m = m; store = new int[n]; // ... } private static class ConstrParams { private int nParam; private int mParam; /* This class can also be used by more than one constructor or independently, to calculate the parameters and store them for other purposes. */ private ConstrParams(Object data) { /* Calculate the parameters and/or do any other operations (preprocessing) that you would do in the specific constructor prior to calling another constructor. You may even add as many auxiliary methods as needed into this class and use them in this constructor. */ nParam = 1; mParam = 2; } } /* Intermediate constructor, the main purpose of which is to extract parameters (if any) from a ConstrParams object and pass them to a primary or an inherited constructor. If ConstrParams produces no parameters but makes some pre-this() or -super() actions, this constructor makes insertion of such actions available. */ private Test(ConstrParams params) { this(params.nParam, params.mParam); /* You can also call super(...) instead of this(...). When calling super(...), primary constructor may even not exist. */ // super(params.nParam, params.mParam); /* As the reference to ConstrParams vanishes upon return to the calling constructor, you may want to make some actions connected with the params object (post-processing) or store the reference to it into this object. If so, here's the right place to do it. Otherwise, no further action is generally needed in this constructor. */ } public Test(Object data) { // Specific constructor. Now compiles successfully. this(new ConstrParams(data)); // ... further initialization } } 

优点包括:

  • 被调用的构造函数的代码不受任何影响。 这在使用super(...)时特别有用,因为对祖先类的更改通常是不合需要的或不可能的。 使用this(...) ,上述方法不会影响依赖主构造函数的任何代码。
  • 它不依赖于被调用构造函数所需的参数数量。 只需添加ConstrParams类字段,然后在调用主要或inheritance的构造函数之前进行提取。 如果参数是联合计算的(即将计算分成两个或多个独立方法是不可能或昂贵的),这种方法可以做到这一点。 当被调用的构造函数不接受任何参数时,可能存在(通常是)情况,并且您只需要在this(...)super(...)调用之前在依赖构造函数中执行某些操作(一个示例)这样的行动是记录)。 此解决方案允许您进行此类操作。
  • 产生参数和/或产生副作用的辅助ConstrParams类可用于其他目的。 如果主类的多个辅助构造函数需要克服this(...)/super(...)调用限制,则可以在其中引入更多构造函数。
  • 统一适用this(...)super(...)调用。