类加载的生命周期
类加载的整个生命周期:加载–验证–准备–解析–初始化–使用–卸载 7个阶段,其中验证、准备、解析部分统称为连接。
类初始化的5中条件
1. 使用new关键字实例化对象的时候,读取或设置一个类的静态字段(该字段不被final修饰)的时候,以及调用一个类的静态方法的时候
2. 使用java.lang.reflect包的方法对类进行反射调用的时候
3. 当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先初始化其父类
4. 当虚拟机启动的时候,用户需要指定一个要执行的主类,虚拟机需要先初始化这个主类
5. 当使用JSK1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REFgetStatic、REFputStatic、REF_invokeStatic的方法句柄,并且这个方法句柄说对应的类没有进行过初始化
类加载过程
加载
- 通过一个类的全限名来获取定义此类的二进制节流。
- 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
- 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
验证
文件格式验证
– [x] 是否以魔数0xCAFEBABE开头
– [x] 主次版本号是否在当前虚拟机处理范围之内
– [x] 常量池中的常量是否有不被支持的常量类型
– [x] 指向常量的各种索引值中是否有指向不存在的常量或不符合类型的常量
– [x] CONSTANTUtf8info型的常量中是否有不符合UTF8编码的数据
– [x] Class文件中各个部分及文件本身是否有被删除的或附加的其他信息
– [x] 等等
元数据验证
– [x] 这个类是否有父类
– [x] 这个类的父类是否继承了不准许被继承的类
– [x] 如果这个类不是抽象类,是否实现了其父类或者接口之中要求实现的所有方法
– [x] 类中的字段方法是否与父类产生矛盾
–
字节码验证
– [x] 保证任意时刻操作数栈的数据类型与指令代码序列都能配合工作
– [x] 保证跳转指令不会跳转到方法体以外的字节码指令上
– [x] 保证方法体重的类型转换是有效的
符号引用验证
– [x] 符号引用中通过字符串描述的全限定名是否找到相应的类
– [x] 在指定的类中是否存在符合方法的字段描述符以及简单名称说描述的方法和字段
– [x] 符号引用中的类、字段、方法的访问性是否被当前类访问
准备
准备阶段是正式为类变量分配内存并设置类变量初始值(被static修饰的变量)的阶段,这些变量所使用的内存都将在方法区中进行分配
解析
解析阶段就是虚拟机将常量池内的符号引用替换为直接引用的过程
初始化
初始化就是执行类构造器方法的过程
类加载器
通过一个类的全限定名来获取描述此类的二进制字节流
类与类加载器
类加载器实现类的加载动作,对于任意类需要通过加载器和这个类本身来确定类的唯一性