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()也有类似的规则。编译器说,调用this必须是构造函数中的第一条语句。
为什么编译器有这些限制?你能给出一个代码例子,如果编译器没有这个限制,就会发生不好的事情吗?
我已经通过链接构造函数和静态方法找到了解决这个问题的方法。我想做的是这样的:
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;
}
}
基本上是根据构造函数的形参构造一个对象,将对象存储在成员中,并将该对象的方法的结果传递到super的构造函数中。使成员为final也是相当重要的,因为类的性质是不可变的。注意,构造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;
}
}
合法的代码,它完成了在调用超级构造函数之前执行多条语句的任务。
父类的构造函数需要在子类的构造函数之前调用。这将确保如果在构造函数中调用父类上的任何方法,父类已经正确设置。
你要做的是,将参数传递给超级构造函数是完全合法的,你只需要像你所做的那样内联构造这些参数,或者将它们传递给你的构造函数,然后将它们传递给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);
}
}
在父类有默认构造函数的情况下,编译器会自动插入对super的调用。由于Java中的每个类都继承自Object,所以必须以某种方式调用Object的构造函数,并且必须首先执行它。编译器可以自动插入super()。强制super首先出现,强制构造函数主体以正确的顺序执行,即:Object -> Parent -> Child -> ChildOfChild -> SoOnSoForth