Java继承体系中main类位置对静态初始化顺序的影响
Java类加载与静态初始化顺序的困惑:main方法位置导致的行为差异
我正在理解Java类加载与继承体系中的静态初始化顺序,发现当main方法所在类不同时,程序表现出不同行为。我准备了两个几乎完全相同的测试用例,仅main方法的位置不同(分别在A1类或A4类中),类结构完全一致。
第一个代码(main方法位于A1类)
package javatest; import java.io.Serializable; class A1 { static { new A2(new A1()); System.out.println("A1-S"); } { System.out.println("A1-N1"); } private A1 a1; public A1() { System.out.println("A1()"); } public A1(A1 a1) { this(); System.out.println("A1(A1)"); this.a1 = a1; new A2(a1); } public void metoda1() { new A1(); System.out.println("A1.metoda1()"); } { System.out.println("A1-N2"); } public static void main(String[] args) { } } class A2 extends A1 implements Serializable { static { System.out.println("A2-S"); } { System.out.println("A2-N"); } protected A2() { System.out.println("A2()"); this.metoda1(); } public A2(A1 a1) { System.out.println("A2(A1)"); a1.metoda1(); } @Override public void metoda1() { super.metoda1(); System.out.println("A2.metoda1()"); } public void metoda2() { System.out.println("A2.metoda2()"); } } class A3 extends A2 { A2 a2 = null; static { System.out.println("a3-S"); } { System.out.println("a3-N1"); } public A3() { super(); System.out.println("a3()"); } public A3(A2 a2) { this(); this.a2 = a2; System.out.println("a3(A2)"); } { System.out.println("a3-N2"); } public A3(A1 a1, A2 a2) { this(a2); System.out.println("a3(A1,A2)"); } public void metoda2() { System.out.println("a3.metoda()"); } } class A4 extends A3 { A1 a1 = new A1(); A3 a2 = new A3(new A1(new A1()), new A2(a1)); Serializable a3 = new A3(); static { System.out.println("A4-S"); } public A4() { super(); System.out.println("A4()"); super.metoda1(); } { System.out.println("A4-N"); } } class A5 extends A1 { static { System.out.println("A5-S"); } public A5() { super(); System.out.println("A5()"); } { System.out.println("A5-N"); } }
第一个代码的输出:
A2-S A1-N1 A1-N2 A1() A1-N1 A1-N2 A1() A2-N A2(A1) A1-N1 A1-N2 A1() A1.metoda1() A1-S
第二个代码(main方法位于A4类)
package javatest; import java.io.Serializable; class A1 { static { new A2(new A1()); System.out.println("A1-S"); } { System.out.println("A1-N1"); } private A1 a1; public A1() { System.out.println("A1()"); } public A1(A1 a1) { this(); System.out.println("A1(A1)"); this.a1 = a1; new A2(a1); } public void metoda1() { new A1(); System.out.println("A1.metoda1()"); } { System.out.println("A1-N2"); } } class A2 extends A1 implements Serializable { static { System.out.println("A2-S"); } { System.out.println("A2-N"); } protected A2() { System.out.println("A2()"); this.metoda1(); } public A2(A1 a1) { System.out.println("A2(A1)"); a1.metoda1(); } @Override public void metoda1() { super.metoda1(); System.out.println("A2.metoda1()"); } public void metoda2() { System.out.println("A2.metoda2()"); } } class A3 extends A2 { A2 a2 = null; static { System.out.println("a3-S"); } { System.out.println("a3-N1"); } public A3() { super(); System.out.println("a3()"); } public A3(A2 a2) { this(); this.a2 = a2; System.out.println("a3(A2)"); } { System.out.println("a3-N2"); } public A3(A1 a1, A2 a2) { this(a2); System.out.println("a3(A1,A2)"); } public void metoda2() { System.out.println("a3.metoda()"); } } class A4 extends A3 { A1 a1 = new A1(); A3 a2 = new A3(new A1(new A1()), new A2(a1)); Serializable a3 = new A3(); static { System.out.println("A4-S"); } public A4() { super(); System.out.println("A4()"); super.metoda1(); } { System.out.println("A4-N"); } public static void main(String[] args) { } } class A5 extends A1 { static { System.out.println("A5-S"); } public A5() { super(); System.out.println("A5()"); } { System.out.println("A5-N"); } }
第二个代码的输出:
A1-N1 A1-N2 A1() A1-N1 A1-N2 A1() A2-N A2(A1) A1-N1 A1-N2 A1() A1.metoda1() A1-S A2-S a3-S A4-S
我已经理解静态初始化块仅在类加载时执行一次等基础概念,但对上述行为仍有困惑。我的推理如下:
- 当main方法位于A4类时,JVM从A4启动,能感知完整的继承层级:A4继承A3,A3继承A2,A2继承A1。因此我认为,在执行A1的静态初始化块时,遇到表达式
new A2(new A1())时,会优先计算内部的new A1(),因为JVM已因继承层级知晓A2,即便A2尚未完成初始化。 - 当main方法位于A1类时,JVM初始仅感知A1,启动时不会主动遍历继承层级。进入A1的静态块后,遇到
new A2(new A1()),JVM首次接触到A2,由于尚未加载并初始化A2,会暂停A1静态块的执行,先去初始化A2,之后再继续执行A1的静态块。
请帮我纠正推理中的错误。
内容的提问来源于stack exchange,提问作者SP222
相关产品推荐
相关产品推荐

