为什么this()和super()必须是构造函数中的第一条语句?
Java要求如果在构造函数中调用this()或super(),它必须是第一条语句。 为什么?
例如:
public class MyClass {
public MyClass(int x) {}
}
public class MySubClass extends MyClass {
public MySubClass(int a, int b) {
int c = a + b;
super(c); // COMPILE ERROR
}
}
Sun编译器说“调用super必须是构造函数中的第一条语句”。 Eclipse编译器说“构造函数调用必须是构造函数中的第一条语句”。
但是,您可以通过稍微重新安排代码来解决此问题:
public class MySubClass extends MyClass {
public MySubClass(int a, int b) {
super(a + b); // OK
}
}
这是另一个例子:
public class MyClass {
public MyClass(List list) {}
}
public class MySubClassA extends MyClass {
public MySubClassA(Object item) {
// Create a list that contains the item, and pass the list to super
List list = new ArrayList();
list.add(item);
super(list); // COMPILE ERROR
}
}
public class MySubClassB extends MyClass {
public MySubClassB(Object item) {
// Create a list that contains the item, and pass the list to super
super(Arrays.asList(new Object[] { item })); // OK
}
}
所以,它不会阻止你在调用super之前执行逻辑 。 它只是阻止你执行不适合单个表达式的逻辑。
调用this()
有类似的规则。 编译器说“调用它必须是构造函数中的第一条语句”。
为什么编译器有这些限制? 你可以给一个代码示例,如果编译器没有这个限制,会发生什么坏事?
父类的constructor
需要在子类的constructor
之前调用。 这将确保如果您在构造函数中的父类上调用任何方法,则父类已正确设置。
你所要做的,将参数传递给超级构造函数是完全合法的,你只需要像内联那样构造这些参数,或者将它们传递给构造函数,然后将它们传递给super
构造函数:
public MySubClassB extends MyClass {
public MySubClassB(Object[] myArray) {
super(myArray);
}
}
如果编译器没有执行这个,你可以这样做:
public MySubClassB extends MyClass {
public MySubClassB(Object[] myArray) {
someMethodOnSuper(); //ERROR super not yet constructed
super(myArray);
}
}
在parent
类具有默认构造函数的情况下, compiler
会自动为您插入对super的调用。 由于Java中的每个类都从Object
继承,因此必须以某种方式调用对象构造函数,并且必须先执行它。 编译器自动插入super()允许这样做。 强制超级先出现,强制执行构造函数体的顺序是:Object - > Parent - > Child - > ChildOfChild - > SoOnSoForth
我通过链接构造函数和静态方法找到了解决这个问题的方法。 我想做的事情看起来像这样:
public class Foo extends Baz {
private final Bar myBar;
public Foo(String arg1, String arg2) {
// ...
// ... Some other stuff needed to construct a 'Bar'...
// ...
final Bar b = new Bar(arg1, arg2);
super(b.baz()):
myBar = b;
}
}
所以基本上是基于构造函数参数构造一个对象,将该对象存储在成员中,并将该对象的方法结果传递给超类的构造函数。 让成员最终决定也是非常重要的,因为这个类的性质是不变的。 请注意,实际上,构建Bar实际上需要一些中间对象,因此在我的实际用例中它不能简化为一行。
我最终使其工作如下所示:
public class Foo extends Baz {
private final Bar myBar;
private static Bar makeBar(String arg1, String arg2) {
// My more complicated setup routine to actually make 'Bar' goes here...
return new Bar(arg1, arg2);
}
public Foo(String arg1, String arg2) {
this(makeBar(arg1, arg2));
}
private Foo(Bar bar) {
super(bar.baz());
myBar = bar;
}
}
法定代码,它在调用超级构造函数之前完成执行多个语句的任务。
因为JLS这样说。 JLS可以以兼容的方式更改以允许它吗? 对。 但是,这会使语言规范复杂化,这已经足够复杂了。 这不是一件非常有用的事情,并且有办法绕过它(用另一个构造函数调用方法this(fn())
- 该方法在另一个构造函数之前调用,因此也是超级构造函数) 。 所以做这个改变的权重比是不利的。
编辑2018年3月:消息记录:构建和验证Oracle建议删除此限制(但与C#不同,在构造函数链接之前, this
将明确未分配(DU))。
历史上,this()或super()必须在构造函数中第一个。 这种限制从来不受欢迎,并且被视为任意。 有许多微妙的原因,包括验证invokespecial,导致了这个限制。 多年来,我们已经在虚拟机级别解决了这些问题,到了考虑解除这一限制变得切实可行的时候,不仅仅是为了记录,而是为了所有构造函数。
链接地址: http://www.djcxy.com/p/59493.html上一篇: Why do this() and super() have to be the first statement in a constructor?