Java类加载过程
所属分类 java
浏览量 971
类从加载到到卸载,整个生命周期包括:加载 验证 准备 解析 初始化 使用和卸载七个阶段
类加载过程包括加载 验证 准备 解析和初始化五个阶段
类加载器 根据一个类的全限定名来读取此类的二进制字节流
然后转换为一个与目标类对应的java.lang.Class对象实例
defineClass方法将字节码byte数组转换为一个类的class对象实例
如果需要类被加载时就链接,可以调用resolveClass方法
双亲委托模型
BootstrapClassLoader ExtClassLoader AppClassLoader
自定义类加载器需要继承抽象类ClassLoader,实现findClass方法,
该方法会在loadClass调用的时候被调用,findClass默认抛异常 ClassNotFoundException
protected Class> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
findClass 根据类名查找类对象
loadClass 根据类名进行双亲委托模型进行类加载并返回类对象
defineClass 根据类的字节码转换为类对象
1 加载
类加载器根据一个类的全限定名读取类的二进制字节流,并存储在运行时内存区的方法区,然后将其转换为一个与目标类型对应的java.lang.Class对象实例
2 链接
将加载到JVM中的二进制字节流的类数据信息合并到JVM的运行时状态中,分验证、准备和解析三个阶段
A 验证
验证类数据信息是否符合JVM规范,是否是一个有效的字节码文件
格式验证、语义分析、操作验证等
格式验证:验证是否符合class文件规范
语义验证:检查一个被标记为final的类型是否包含子类;检查一个类中的final方法视频被子类进行重写;确保父类和子类之间没有不兼容的一些方法声明(比如方法签名相同,但方法的返回值不同)
操作验证:在操作数栈中的数据必须进行正确的操作,对常量池中的各种符号引用执行验证(通常在解析阶段执行,检查是否通过富豪引用中描述的全限定名定位到指定类型上,以及类成员信息的访问修饰符是否允许访问等)
B 准备
为类中的所有静态变量分配内存空间,并为其设置一个初始值
被final修饰的静态变量,会直接赋予原值;
类字段的字段属性表中存在ConstantValue属性,则在准备阶段,其值就是ConstantValue的值
C 解析
将常量池中的符号引用转为直接引用(得到类或者字段、方法在内存中的指针或者偏移量,以便直接调用该方法),这个可以在初始化之后再执行。
可以认为是一些静态绑定的会被解析,动态绑定则只会在运行时进行解析
静态绑定包括一些final方法(不可以重写),static方法(只会属于当前类),构造器(不会被重写)
3 初始化
将一个类中所有被static关键字标识的代码统一执行一遍,
如果执行的是静态变量,那么就会使用用户指定的值覆盖之前在准备阶段设置的初始值;
如果执行的是static代码块,那么在初始化阶段,JVM就会执行static代码块中定义的所有操作。
所有类变量初始化语句和静态代码块都会在编译时被前端编译器放在收集器里头,
存放到一个特殊的方法中,这个方法就是 clinit 方法,即类/接口初始化方法。
该方法的作用就是初始化一个中的变量,使用用户指定的值覆盖之前在准备阶段里设定的初始值。
任何invoke之类的字节码都无法调用 clinit 方法,因为该方法只能在类加载的过程中由JVM调用。
如果父类还没有被初始化,那么优先对父类初始化,
但在 clinit 方法内部不会显示调用父类的 clinit 方法,
由JVM负责保证一个类的 clinit 方法执行之前,它的父类 clinit 方法已经被执行。
JVM必须确保一个类在初始化的过程中,
如果是多线程需要同时初始化它,仅仅只能允许其中一个线程对其执行初始化操作,
其余线程必须等待,只有在活动线程执行完对类的初始化操作之后,才会通知正在等待的其他线程。
java类加载知识点
类加载器中findClass与loadClass的区别
java类加载器要点整理
自定义类加载器例子
上一篇
下一篇
基于netty的RESTFUL框架
Java动态代理InvocationHandler例子
Linux常用命令汇总
2020热词中英文
Java字节码增强简介
JDK CGLIB Javassist ASM 动态代理 比较