我有以下代码:
class Foo {
static { //static initializer block
System.out.print("Foo");
}
class Bar {
static { //static initializer block
System.out.print("Bar");
}
}
public static void main(String[] args) { // => This will print "FooBar" to the console
new Foo().new Bar();
}
}
public class Main {
public static void main(String[] args) { // This will print "BarFoo" to the console
new Foo().new Bar();
}
}
正如注释所说,它们将在独立调用主方法时打印不同的结果。为什么在这种情况下 main 方法的放置会影响打印到屏幕上的结果?
最佳答案
new Foo().new Bar()
被编译为以下字节码:
NEW Foo$Bar
DUP
NEW Foo
DUP
INVOKESPECIAL Foo.<init> ()V
INVOKESPECIAL Foo$Bar.<init> (LFoo;)V
请注意,首先创建的是 Bar
(尽管首先调用的是 Foo
的构造函数)。 new
指令导致类被初始化(参见 spec ),而不是构造函数调用。当初始化一个类时,它的静态初始化程序会运行(请参阅 spec )。
以防万一您不知道,非静态内部类是通过让构造函数采用额外参数来实现的,该参数用作封闭实例。 new Foo().new Bar()
基本上是在说 new Foo.Bar(new Foo())
,但只有前一种语法才有效。
我不确定这样的输出是否是规范所保证的行为。从技术上讲,它可以以先出现 NEW Foo
的方式进行编译,但这需要一个额外的变量,就像您编写的那样:
var f = new Foo();
f.new Bar();
因此,当您将 new Foo().new Bar()
放入不相关的类中时,Bar
首先被初始化,因此 Bar
首先打印。
但是,当您将 new Foo().new Bar()
放入 Foo
中声明的静态方法中时,Foo
将被初始化在任何 new
指令之前,因此首先打印 Foo
。这是因为在 Foo
中调用静态方法会导致 Foo
被初始化。
查看要在 spec 中初始化类或接口(interface) T
的所有条件:
T is a class and an instance of T is created.
A static method declared by T is invoked.
A static field declared by T is assigned.
A static field declared by T is used and the field is not a constant variable (§4.12.4).
请注意,第一个指的是 new
指令的执行,而不是构造函数调用。
关于java - 在外部类和内部类之间,在外部类内部或外部调用 main 方法时,它们的静态初始化程序运行顺序不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77148390/