类的加载过程
一、类的加载阶段
类的加载阶段,其实就是将class字节码文件中的二进制数据读取到内存之中,然后将文件所代表的静态存储结构,转换为方法区中运行时的数据结构,并且在堆内存中生成一个该类的java.lang.Class对象,作为访问方法区数据结构的入口。
而在同一个类加载器下,无论一个类被加载多少次,堆内存里面的Class对象都只有唯一 的一个。
而加载的方式也不仅仅是字节码文件或者说字节流的形式,还有我们都知道的动态代理,可以运行时动态生成字节码的字节流,从jar包中获取字节流等等,加载阶段不局限一种形式。
二、类的连接阶段
1、验证
验证字节流的信息是否符合JVM的规范,保证不会出现危害JVM的代码。一般就是验证这个文件的格式,也就是头部信息是不是class文件,还有版本号,用高版本编译的文件是不能被低版本的兼容的;验证元数据的继承等进行语义分析是否合法;验证代码的控制流程等;还有就是符号引用的验证。
2、准备
经过了验证之后,就会开始对该类对象的变量分配内存,并且设置初始值,而类变量的内存是分配在方法区中的,不同于实例变量。
3、解析
这个阶段,其实就是把部分符号引用替换成直接引用。比如说
1 public class Tes1{ 2 static Simple simple; 3 4 public static void main(String[] args) { 5 System.out.println(simple); 6 } 7 }
在方法中引用了simple,那么在解析阶段就会在常量池找simple的符号引用,然后对simple加载,然后符号引用就会转换成直接引用,也就是simple的内存地址。
三、类的初始化阶段
在这个阶段中,主要就是执行<clinit>()方法,在方法中,所有的类变量都会被赋予正确的值,以及执行静态语句块。
<clinit>()这个方法是在编译阶段,由编译器自动生成在class文件中的,方法里面的执行顺序与源代码中的书写顺序是一致的!!!也就是说这个方法里面是可以保证执行顺序的!!!!而且JVM会保证父类的<clinit>()先执行。除此之外,这个方法在多线程环境下,JVM会保证它的同步语义,有且仅有一个线程执行<clinit>(),并且只会执行一次。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?