JVM篇(六)--类加载过程

本文详细介绍了Java类加载执行过程,包括类加载子系统的功能,类加载、链接和初始化阶段的具体操作。类加载阶段读取字节码文件,链接阶段包含验证、准备和解析步骤,初始化阶段对类变量和静态代码块赋值。还说明了Class创建的时机及初始化的相关要点。

1.类加载执行过程

类加载子系统处于中间位置,它前面是一个字节码文件,有了字节码文件需要类加载子系统进行读取,对.class文件的规格进行检查判断,然后在将常量池也好,字段与发放的描述按照规则加载到JVM内存中存储,类加载子系统就相当于运行时数据区的入口所在

1.1 类加载子系统介绍

 1.类加载子系统负责从文件或者网络加载Class字节流,(类文件不一定都是在此磁盘的,只要符合这个字节流,通过网络或者其他介质都是可以加载的)

  2.类加载子系统会读取字节码中的信息,运行时存储到jvm中

  3.任何Class要被类加载子系统加载,都要符合JVM的规范

1.2 类加载执行过程

类先判断是否被加载过,没有的话去加载类到jvm的内存中存储,在内存中就拥有了字节码的信息,但是还没有生效,因为还没有验证需要进入第二阶段。

链接阶段:又分为验证、准备、解析

验证阶段就是将刚存储的字节码信息按jvm的规范进行校验,比如前4个字节是不是cafe xxxx ,后四个字节是不是版本号等等,验证都是在这个阶段完成的

准备阶段:就是将类的成员变量赋给默认的值,比如 int 类型的就会赋值成0。

解析阶段:比较复杂,就是在字节码中的符号引用转换为内存中的直接引用。

最后阶段初始化:类变量静态代码块赋予真正的变量值

根据这三个类的初始化就完成了,后续就可以进行实际运行,根据初始化的类,程序就可以对对象进行实例化的工作,后面会分别讲解这几个过程

2.类加载阶段

类加载阶段主要的事情是 字节码文件的数据以二进制流的方式被jvm中的类加载器进行读取和加载,在这个过程中做了如下几件事情:

1.类加载器读取字节码二进制流(读文件)

2.解析字节码二进制流的静态数据转换为运行时JVM放法区数据。(方法区时很重要的区域,类、字段、方法,常量信息都在内存运行时存储到方法区中)

3.解析完成以后,生成类的java.lang.Class,类对象会存放到堆中,作为方法区的访问入口。

4.在加载类的过程中,比如会触发父类加载(子类加载,父类也会按照上面1-3依次进行加载处理操作)

一个A.class字节码文件,类加载器会判断运行时数据区是否有A类呢?如果没有的话,类加载器进行读取A类字节码文件,读取的同时也会分析A类,发现A类文件是有继承关系的BaseA,那么类加载器就会先加载BaseA,这里有两个区域,BaseA与A都有对应的方法区存储的数据,以及字节对应对象的实例就是堆区,也就是说A类里的字节码文件的信息是放在方法区,通过A的class实例就可以获得对应类的字段和方法。

一个Class字节码文件被类加载器加载,如果有父类先加载父类,在加载子类,会加载到堆区的对应实例作为入口,可以访问方法区中所对应的字段等等信息

Class何时被创建?

1.new实例化时: A a=new A();

2.反射:Class clza=Class.forName("xx.xx.A");

3.子类加载时父类同时加载

4.JVM启动时,包含main方法的主体会被加载,以及所有对象对的父类都时Object,所以程序启动前必有Object的类

5. 1.7动态类型语言支持

3.类链接(Linking)阶段

链接阶段有三个步骤:

1.验证(verify):确保字节码符合虚拟机要求

2.准备(prepare):为字段赋予初始值

3.解析(resolve):符号引用转为直接引用

2.1 验证阶段

验证阶段的内容基本就是以下图的内容:

验证阶段和加载阶段是交替执行的,读取的二进制流就可以直接验证,这里的验证阶段不是对运行时环境加载内存的操作,只是对二进制操作,是否符合条件

1.文件格式校验:前4个字节是否时CAFEBABE,后面4个字节是否时版本号等等

2.元数据匹配语义分析:是否是正确能被使用的语义

3.字节码校验,数据流与控制流分析:平常接触的类型转换是否有校,返回值缺少,还是到哪里不需要返回值等等

4.符号引用:能否找到类、方法等信息

2.2 准备阶段

为static值赋值成初始值,不同类型赋予不同的值,图下的表格是不同的值的初始值,什么时候赋值成真正的值呢,那需要在初始化阶段,初始化阶段是类加载最后一个阶段

2.3 解析阶段

链接中的最后一个操作,将符号引用转换为直接引用,也就是上图中说明,

符号引用:静态字面  

直接引用:动态指针关联

对上面的图 A类,它的父类是BaseA类,符号引用就是用字符串字面的表达方式说明A与BaseA的关系,this class:A     superClass:BaseA,以这种方式说明他们的关系。

在程序运行中A与BaseA是一个实例,他们的关系需要动态的指针去关联,当然知道是什么关系是通过字符串字面去转换指针关联的

解析阶段对哪些事物进行解析呢?

  1. 类解析
  2. 字段解析
  3. 方法解析
  4. 接口解析

1.4 类初始化阶段

初始化阶段是对类的初始阶段对clint方法的执行。

 

1.初始化阶段就是对类变量以及静态变量进行初始化的。

2.子类初始化按照正常加载逻辑,子类创建对象当知道有父类的时候会优先加载父类,那么这里也是子类初始化会优先执行父类的初始化

3.没有类变量和静态代码就不会产生clint(初始化)

4.jvm启动可以选择加+TraceClassLoading来查看类加载顺序,帮助学习

5.为了只初始化依次,初始化方法会加同步锁

咱们用代码演示下:

ClassInitSamples是子类,继承Base类

ClassInitSamples有两个静态类变量,还有一个静态代码块,代码块里的代码是对类变量赋值操作。然后main方法new ClassInitSamples类

父类也有一个静态变量和静态代码块,

测试启动子类的main方法发现父类的初始化是需要先执行的。

如果此时你用JCLASSlIb查看字节码文件,能看到有Clint初始方法。当然此时把类变量和静态方法块去掉,你要是用JCLASSlIb就可以查看字节码里没有了clint了。

 

在vm加入此单词,运行就会把加载顺序过程展示出来

后面就不一一测试了,初始化的知识点概括在以下几点:

 

 

评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值