正如一些消息来源所说,Java实例初始化块在创建实例时或在构造函数之前执行。但想象一下这个案例:
public class Foo {
{
System.out.println("Foo init");
}
public Foo()
{
{
System.out.println("Foo constr");
}
}
}
public class Main extends Foo {
{
System.out.println("Main init");
}
public Main()
{
{
System.out.println("Main constr");
}
}
public static void main(String[] args) {
new Main();
}
}
输出是(如预测的那样):
Foo init
Foo constr
Main init
Main constr
所以我的问题是 - 实例初始化块的正确定义是什么,因为它显然不是在构造函数之前执行,因为输出应该是
Main init
Foo init
Foo constr
Main constr
因为Main()构造函数在调用super()之前被调用,而Main初始化块应该是第一个。
答案 0 :(得分:4)
没有。初始化块直接复制到构造函数中。显然,那里也有一个隐含的超级。所以你的例子变成了
public class Foo {
public Foo()
{
{System.out.println("Foo init");} // initializer.
{System.out.println("Foo constr");}
}
}
public class Main extends Foo {
public Main()
{
super(); // super constructor.
{System.out.println("Main init");} // initializer.
{System.out.println("Main constr");}
}
public static void main(String[] args) {
new Main();
}
}
这解释了您观察到的行为
Foo init
Foo constr
Main init
Main constr
答案 1 :(得分:0)
new Main();
上述状态将首先转到Main()。但是在Main()中执行任何操作之前,都会调用super()。所以,调用Foo()。现在,在Foo()中进行检查以查看实例初始化块。所以,你明白了。 “Foo init”。接下来执行Foo()中的语句。所以,你得到 - “Foo constr”。接下来,控件返回到Main(),Main()现在检查Main类是否存在初始化块。因此,打印“Main Init”..然后打印Main()的其他语句。定义是正确的..理解......好......取决于你怎么看......
答案 2 :(得分:0)
最后一个陈述不正确。在 Foo()之后执行Main(),因为类构造函数在其超级构造函数完成后执行。 有关更多详细信息,请参阅this part of the spec,,其中涉及隐式和显式超级构造函数调用。
答案 3 :(得分:0)
编译器将代码转换为如下代码:
public class Main extends Foo {
void _init()
{System.out.println("Main init");}
public Main()
{
super();
_init();
{System.out.println("Main constr");}
}
}
主要规则是:
答案 4 :(得分:0)
在JLS中有一个specific initialization procedure解释,但让我提炼出最关键的部分:
这就是为什么你看到你所做的行为 - 因为Main
是Foo
的子类,它还没有被初始化,所以那时它的静态块没有被评估。 / p>
因此,Main
的构造函数直到Foo
的构造函数之后才会执行,因为子类中有an implicit call to super()
。
答案 5 :(得分:0)
了解此代码在内部的工作原理:
class Foo {
{System.out.println("Foo init");}
public Foo()
{
{System.out.println("Foo constr");}
}
}
class Main extends Foo {
{System.out.println("Main init");}
public Main()
{
{System.out.println("Main constr");}
}
public static void main(String[] args) {
new Main();
}
}
步骤1:JVM调用main()
类
Main
方法
步骤2:构造函数Main()
具有内部super()
,如果您不使用this()
,则由JVM提供,因此super将调用超级构造函数,即超级Foo()
类。
步骤3:现在在调用超类的Foo之前,JVM将检查是否有IIB
即实例初始化块,因此,在打印“Foo constr”之前将打印“Foo init”
现在输出到现在是:
Foo init
Foo constr
步骤4:我们的控制返回到当前构造函数并在执行之前再次执行当前的construstor JVM将调用IIB
,即实例初始化块和“Main init”将被打印。然后最后“主要建设”
所以最后是:
Foo init
Foo constr
Main init
Main constr
实际上,任何构造函数的第一次调用始终是Super()
或this()
。
你正在使用new Main();
创建新对象,当然这将调用构造函数,总是调用构造函数来初始化对象。