在下面的代码中,为什么getX()
方法首先执行而不是构造函数:
public class ConsructorQuestion {
int x = getX(); // same this.getX();
public int getX() {
System.out.println(x + " via method ");
return 10;
}
public ConsructorQuestion() {
System.out.println(x+" via constructor");
}
public static void main(String[] args) {
ConsructorQuestion t = new ConsructorQuestion();
}
}
答案 0 :(得分:6)
在执行构造函数体之前(但在执行超类构造函数的主体之后)初始化实例变量。
因此,在您的示例中,int x = getX();
在构造函数体之前执行。
这相当于将x
的初始化移动到构造函数的第一行:
int x;
public int getX(){
System.out.println(x+" via method ");
return 10;
}
public ConsructorQuestion() {
x = getX();
System.out.println(x+" via constructor");
}
答案 1 :(得分:5)
如果构造函数没有链接到另一个构造函数,则编译器将字段初始化程序(和实例初始化块)注入到类中每个构造函数的开头(在调用super(...)
之后,隐式或显式)在同一个班级(通过调用this(...)
)。因此,如果您查看生成的字节码,您会看到您的类看起来像这样:
public class ConsructorQuestion {
int x; // ***
public int getX(){
System.out.println(x+" via method ");
return 10;
}
public ConsructorQuestion() {
this.x = getX(); // ***
System.out.println(x+" via constructor");
}
public static void main(String[] args) {
ConsructorQuestion t = new ConsructorQuestion();
}
}
构造实例时完成任务的顺序由JLS§12.5:
涵盖在作为结果返回对新创建的对象的引用之前,处理指示的构造函数以使用以下过程初始化新对象:
将构造函数的参数分配给此构造函数调用的新创建的参数变量。
如果此构造函数以同一个类中的另一个构造函数的显式构造函数调用(第8.8.7.1节)开头(使用此方法),则使用这五个相同步骤计算参数并以递归方式处理该构造函数调用。如果该构造函数调用突然完成,则此过程突然完成,原因相同;否则,继续步骤5.
此构造函数不以同一类中另一个构造函数的显式构造函数调用开头(使用此方法)。如果此构造函数用于Object以外的类,则此构造函数将以超类构造函数的显式或隐式调用开始(使用super)。使用这五个相同的步骤评估参数并递归处理超类构造函数调用。如果该构造函数调用突然完成,则此过程突然完成,原因相同。否则,请继续执行步骤4.
为此类执行实例初始值设定项和实例变量初始值设定项,将实例变量初始值设定项的值按从左到右的顺序分配给相应的实例变量,它们在源中以文本方式显示该类的代码。如果执行任何这些初始值设定项导致异常,则不会处理其他初始值设定项,并且此过程会突然完成同样的异常。否则,请继续步骤5.
- 醇>
执行此构造函数的其余部分。如果执行突然完成,则此过程突然完成,原因相同。否则,此过程正常完成。
请注意#4和#5的顺序。
答案 2 :(得分:0)
Javac从类的开头开始,首先初始化类成员,然后继续使用main。