Java类加载过程

类加载过程分为加载、连接、初始化,连接过程又可分为验证、准备、解析

加载

使用类加载器将class文件加载到JVM中,加载阶段会将类的元数据(方法、字段、类名等)存储到方法区,然后在堆中生成Class对象,Class对象持有引用,指向方法区中的类的元信息。

连接

验证

验证字节码的文件格式、语法、内容等,确保字节码符合JVM规范。

验证内容:

  • ​文件格式验证:魔数(0xCAFEBABE)、版本号等。
  • ​元数据验证:类是否有父类、是否继承 final 类等语义检查。
  • ​字节码验证:确保指令不会导致 JVM 崩溃(如操作数栈溢出)。
  • ​符号引用验证:检查引用的类、方法、字段是否存在。

准备

为静态变量分配内存,并设置初始值。

准备阶段会给静态变量设置初始值,如下:

给b设置一个初始值0,初始化阶段再赋值为10;

对于基本类型和String的常量,会直接在准备阶段设置为我们赋予的值,c赋值为20,d赋值为"hello"。

对于其余引用类型的常量会在初始化阶段赋值

解析

将常量池内的符号引用替换为直接引用。

符号引用是类的元数据(字段、方法、类名等)的字符串,存储在常量池中。

直接引用是类的元数据的内存地址。

初始化

调用clinit方法对静态代码、静态代码块进行初始化。

对于初始化阶段,虚拟机严格规范了有且有 6 种情况下,必须对类进行初始化(只有主动去使用类才会初始化类):

  • 当遇到 newgetstaticputstaticinvokestatic 这 4 条字节码指令时,比如 new 一个类,读取一个静态字段(未被 final 修饰)、或调用一个类的静态方法时。
    • 当 jvm 执行 new 指令时会初始化类。即当程序创建一个类的实例对象。
    • 当 jvm 执行 getstatic 指令时会初始化类。即程序访问类的静态变量(不是静态常量,常量会被加载到运行时常量池)。
    • 当 jvm 执行 putstatic 指令时会初始化类。即程序给类的静态变量赋值。
    • 当 jvm 执行 invokestatic 指令时会初始化类。即程序调用类的静态方法。
  • 使用 java.lang.reflect 包的方法对类进行反射调用时如 Class.forName("..."), newInstance() 等等。如果类没初始化,需要触发其初始化。
  • 初始化一个类,如果其父类还未初始化,则先触发该父类的初始化。
  • 当虚拟机启动时,用户需要定义一个要执行的主类 (包含 main 方法的那个类),虚拟机会先初始化这个类。
  • MethodHandleVarHandle 可以看作是轻量级的反射调用机制,而要想使用这 2 个调用,
    就必须先使用 findStaticVarHandle 来初始化要调用的类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值