从类加载的角度看static、main、构造方法的执行顺序

本文通过示例代码深入解析Java中类的加载过程及static、main方法、构造方法等的执行顺序,揭示了Java程序运行时的具体行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先先放上我们写的一个.Java文件的前世今生。

现在上代码,查看static,main,构造方法的执行顺序

public class ClassA {

    // 定义静态变量
    public static ClassA classa = new ClassA();
    
    static {
        System.out.println("ClassA的静态代码块");
    }

    public ClassA() {
        System.out.println("ClassA的构造方法");
    }

    //构造代码块
    {
        System.out.println("ClassA的构造代码块");
    }
}

public class ClassB extends ClassA {

    static {
        System.out.println("ClassB的静态代码块");
    }

    public ClassB() {
        System.out.println("ClassB的构造方法");
    }

    {
        System.out.println("ClassB的构造代码块");
    }

    public static ClassC classc = new ClassC();

    public void excute() {
        System.out.println("执行方法");
    }
}
public class ClassC {

    public ClassC() {
        System.out.println("ClassC的构造方法");
    }
}

测试类

public class Test {

    static {
        System.out.println("Test的静态代码块");
    }

    public static void main(String[] args) {
        System.out.println("执行main方法");
        ClassB b = new ClassB();
        b.excute();
    }
}

输出的结果为

-

-

-

1                 Test的静态代码块
2                 执行main方法
3                ClassA的构造代码块
4                ClassA的构造方法
5                ClassA的静态代码块
6                ClassB的静态代码块
7                ClassC的构造方法
8                ClassA的构造代码块
9                ClassA的构造方法
10              ClassB的构造代码块
11              ClassB的构造方法
12              执行方法

结合上图这里解释下原因

一.首先main方法是一个程序的入口,所以它所在的类优先加载也优先执行,在执行完类的全部加载过程(加载、验证、准备、解析、初始化)后main方法才会进行执行

二.static关键字修饰的变量或者代码块,是在准备阶段加载的,多个同级别static变量或者代码块是按照定义的前后顺序执行的

三.当创建一个子类对象的时候(调用构造方法)首先会调用父类的构造方法

四.构造代码块是依赖于构造方法存在的,会在每个构造方法中都添加上构造代码块的代码(下面多说明)

详细说明下:

main方法是程序的入库,所以所在类Test优先加载和执行,当Test类进行类加载的准备阶段就执行了Test类的静态代码块,等Test类完成初始化后才执行main方法。(解释前两个输出)

接下来是要去ClassB的实例,ClassB继承了ClassA所以这里先操作ClassA类,也就是ClassA进行加载,里面有静态变量和静态代码块,根据上面说的第二点,知道先执行 public static ClassA classa = new ClassA();调用A类的构造方法创建A实例,因为存在构造代码块,构造方法在执行前一定会先执行了构造代码块的代码。(解释3和4的输出)

创建完A实例,继续按顺序执行静态代码(解释5)

父类文件加载完开始进行子类文件重复上面的原因(解释6、7)

至此类都加载完了执行B的构造方法,根据第四点知道要先执行A类的构造方法(解释8、9、10、11)

再详细说一下第四点,为什么说构造代码块是依赖于构造方法存在的,可以理解为构造代码块不会单独执行,一定要和构造方法一起执行。这里对ClassA的字节码文件进行反编译ClassA.class结果为

public class ClassA
{
  public static ClassA classa = new ClassA();

  static { System.out.println("ClassA的静态代码块");
  }

  public ClassA()
  {
    System.out.println("ClassA的构造代码块");

    System.out.println("ClassA的构造方法");
  }
}

构造代码块不存在了,直接变成了在构造方法里面,并且放在构造方法原代码的前面。

这里是一个构造方法,如果有多个构造方法呢?这里在添加一个有参的构造方法,内容为直接输入参数,直接贴反编译后的结果

public class ClassA
{
  public static ClassA classa = new ClassA();

  static { System.out.println("ClassA的静态代码块");
  }

  public ClassA()
  {
    System.out.println("ClassA的构造代码块");

    System.out.println("ClassA的构造方法");
  }

  public ClassA(String str)
  {
    System.out.println("ClassA的构造代码块");

    System.out.println(str);
  }
}

从结果上可以看出,有多个构造方法是,每个构造方法里的最前面都会填充上构造代码块的代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

亚马特

感觉有用,就给点打赏吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值