Java虚拟机之类加载

2019-04-02  本文已影响0人  末日声箫

一,类文件结构

Class文件是一组以8字节为基础单位的二进制流。各个数据严格按照顺序紧凑地排列在Class文件中。

Class文件包含两种数据类型:无符号数和表

无符号数:u1,u2,u4,u8(分别代表1,2,4,8字节)

表:由多个无符号数或者其它表作为数据项构成的复合数据类型。所有表习惯性以“.info”结尾

class文件中的每个字节,长度,先后顺序都是被严格控制,不允许改变。

class文件结构:

魔数——class文件版本——常量池——访问标志——类索引,父类索引与接口索引集合——字段表集合——方法表集合——属性表集合(关于这部分可以直接通过javap反编译出来,笔者再此不作过多介绍)

二,类加载机制

类加载过程.png

类加载的生命周期:加载-验证-准备-解析-初始化-使用-卸载

为了支持java语言的动态绑定,除了加载-验证-准备-初始化-卸载 这5个阶段的先后次序是确定的,其余的都不是。

2.1 类加载过程

加载 :

验证:确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全

准备:为类变量(static修饰的变量)分配内存和设置初始值(数据类型的零值)。

如果变量还加有final修饰,则准备阶段就将其值初始化为指定的值。

解析:虚拟机将常量池内的符号引用替换为直接引用的过程。

初始化:初始化是类加载的最后一步,初始化是执行类构造器<clinit>()的过程。

进行初始化的条件:

当执行testSub()方法的时候:

super init
test

可见子类并没有被初始化。因为通过子类来调用父类的静态变量时,父类满足上诉第一条,父类被初始化,而子类不满足上述五条的任何一条,所以不会输出:sub init

当执行finalTest()方法时:

finalTest

并没有输出 super init 。这是因为 finale 修饰的字段在准备阶段就已经被加入到test类常量池里面去了,而super类不满足上诉五种条件中的一种,所以不会被初始化。

当执行staticTest 方法时:

super init
sub init
2

这里sub 类也被初始化了,因为调用了sub类的静态变量,符合1,而值时2,说明了父类的初始化会在子类之前完成,这里验证了下面的2

初始化注意的点:

2.2 类加载器

对于任何一个类都需要它的类加载器和这个类本身一同确定其在虚拟机中的唯一性。

从虚拟机角度来看只有两种类加载器:启动类加载器和其它。

从java开发者角度来说,有三种:启动类加载器,扩展类加载器,应用程序加载器

双亲委派模型 :

双亲委派模型.png

如果一个类加载器收到了类加载的请求,他首先会委派给父类加载器去完成,如果父类无法完成,则子类才会去尝试。

上一篇 下一篇

猜你喜欢

热点阅读