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.4 类初始化阶段
初始化阶段是对类的初始阶段对clint方法的执行。
1.初始化阶段就是对类变量以及静态变量进行初始化的。
2.子类初始化按照正常加载逻辑,子类创建对象当知道有父类的时候会优先加载父类,那么这里也是子类初始化会优先执行父类的初始化
4.jvm启动可以选择加+TraceClassLoading来查看类加载顺序,帮助学习
5.为了只初始化依次,初始化方法会加同步锁
咱们用代码演示下:
ClassInitSamples是子类,继承Base类
ClassInitSamples有两个静态类变量,还有一个静态代码块,代码块里的代码是对类变量赋值操作。然后main方法new ClassInitSamples类
如果此时你用JCLASSlIb查看字节码文件,能看到有Clint初始方法。当然此时把类变量和静态方法块去掉,你要是用JCLASSlIb就可以查看字节码里没有了clint了。
在vm加入此单词,运行就会把加载顺序过程展示出来
后面就不一一测试了,初始化的知识点概括在以下几点:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。