在调用super(...)或this(...)构造函数之前,有什么方法可以实现初步计算?考虑以下示例:
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(...)因为我们得到在这种情况下缺乏灵活性,往往不能改变父类的代码更是雪上加霜。
Test(Object data)
这是我发现的一种通用方法。它允许在调用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 } }
优势包括:
ConstrParams
this(...)/super(...)