你能给出一个代码例子,如果编译器没有这个限制,就会发生不好的事情吗?
class Good {
int essential1;
int essential2;
Good(int n) {
if (n > 100)
throw new IllegalArgumentException("n is too large!");
essential1 = 1 / n;
essential2 = n + 2;
}
}
class Bad extends Good {
Bad(int n) {
try {
super(n);
} catch (Exception e) {
// Exception is ignored
}
}
public static void main(String[] args) {
Bad b = new Bad(0);
// b = new Bad(101);
System.out.println(b.essential1 + b.essential2);
}
}
An exception during construction almost always indicates that the object being constructed could not be properly initialized, now is in a bad state, unusable, and must be garbage collected. However, a constructor of a subclass has got the ability to ignore an exception occurred in one of its superclasses and to return a partially initialized object. In the above example, if the argument given to new Bad() is either 0 or greater than 100, then neither essential1 nor essential2 are properly initialized.
你可能会说忽略异常总是一个坏主意。好的,这里还有一个例子:
class Bad extends Good {
Bad(int n) {
for (int i = 0; i < n; i++)
super(i);
}
}
很有趣,不是吗?在这个例子中我们创建了多少个对象?一个?两个?或者什么都没有……
允许在构造函数中间调用super()或this()将打开一个令人讨厌的构造函数的潘多拉盒子。
另一方面,我理解在调用super()或this()之前经常需要包含一些静态部分。这可能是任何不依赖于此引用的代码(实际上,它已经存在于构造函数的最开始,但在super()或This()返回之前不能有序使用),并且需要进行这样的调用。此外,像在任何方法中一样,在调用super()或this()之前创建的一些局部变量可能会在调用super()或this()之后被需要。
在这种情况下,你有以下机会:
Use the pattern presented at this answer, which allows to circumvent the restriction.
Wait for the Java team to allow pre-super() and pre-this() code. It may be done by imposing a restriction on where super() or this() may occur in a constructor. Actually, even today's compiler is able to distinguish good and bad (or potentially bad) cases with the degree enough to securely allow static code addition at the beginning of a constructor. Indeed, assume that super() and this() return this reference and, in turn, your constructor has
return this;
最后。以及编译器拒绝代码
public int get() {
int x;
for (int i = 0; i < 10; i++)
x = i;
return x;
}
public int get(int y) {
int x;
if (y > 0)
x = y;
return x;
}
public int get(boolean b) {
int x;
try {
x = 1;
} catch (Exception e) {
}
return x;
}
with the error "variable x might not have been initialized", it could do so on this variable, making its checks on it just like on any other local variable. The only difference is this cannot be assigned by any means other than super() or this() call (and, as usual, if there is no such call at a constructor, super() is implicitly inserted by compiler in the beginning) and might not be assigned twice. In case of any doubt (like in the first get(), where x is actually always assigned), the compiler could return an error. That would be better than simply return error on any constructor where there is something except a comment before super() or this().