以下代码的输出结果是?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class StaticTest {

public static StaticTest t1 = new StaticTest();
public static StaticTest t2 = new StaticTest();

static {
System.out.println("静态块");
}

{
System.out.println("构造块");
}

public static void main(String[] args) {
StaticTest t = new StaticTest();
}
}

A. 静态块 构造块 构造块 构造块
B. 构造块 静态块 构造块 构造块
C. 构造块 构造块 静态块 构造块
D. 构造块 构造块 构造块 静态块

1
2
3
4
5
6
7
$ /Library/Java/JavaVirtualMachines/jdk-13.0.2.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=51677:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Users/onns/Documents/code/java/jvm/out/production/jvm xyz.onns.nowcoder.StaticTest
构造块
构造块
静态块
构造块

Process finished with exit code 0
  1. 开始时 JVM 加载 StaticTest.class,对所有的静态成员进行声明,t1、t2 被初始化为默认值null
  2. 又因为 t1、t2 需要被显式初始化,所以对 t1 进行显式初始化,初始化代码块 → 构造函数(没有就是调用默认的构造函数)。
  3. 因为在开始时已经对 static 部分进行了初始化,虽然只对 static 变量进行了初始化,但在初始化 t1 时也不会再执行 static 块了,因为 JVM 认为这是第二次加载类 B 了,
  4. 所以 static 会在 t1 初始化时被忽略掉,所以直接初始化非 static 部分,也就是构造块部分(输出’构造块’)接着构造函数(无输出)。
  5. 接着对 t2 进行初始化过程同 t1 相同(输出’构造块’)。
  6. 此时就对所有的 static 变量都完成了初始化,接着就执行 static 块部分(输出’静态块’)。
  7. 接着执行,main 方法,同样也,new 了对象,调用构造函数输出(‘构造块’)。

#进阶

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//父类
public class B {
public static B t1 = new B();
public static B t2 = new B();
public B(){
super();
System.out.println("B类构造块");
}
static {
System.out.println("B类静态块");
}
}
//子类
public class A extends B {
public static A t1 = new A();
public static A t2 = new A();
public A(){
super();
System.out.println("A类构造块");
}
static {
System.out.println("A类静态块");
}
public static void main(String[] args) {
A t = new A();
}
}

#参考链接