You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 17:34:54