JVM的类加载问题
1. 加载.class文件的方式
1)从本地系统中直接加载
2)通过网络下载.class文件
典型场景:Web Applet (小程序应用)
3)从zip,jar等归档文件中加载.class文件
典型场景:后续演变为jar/war格式
4)从专有数据中提取.class文件
典型场景:JSP应用从专有数据库中提取.class文件, 比较少见
5)将Java文件动态编译为.class文件,运行时计算而成
典型场景:动态代理
6)将Java文件动态编译为.class文件,运行时计算而成
典型场景:动态代理
7)从加密文件中获取
典型场景:典型的防Class文件被反编译的保护措施
2. 类加载流程
装载 -> 链接(验证、准备、解析) -> 初始化
所谓的类加载机制就是:
虚拟机把Class文件加载到内存
并对数据进行校验,转换解析和初始化
形成虚拟机可以直接使用的Java类型,即java.lang.Class
2.1 装载(Load)
查找和导入.class文件
1)通过一个类的全限定名获取定义此类的二进制字节流
2) 将字节流所代表的静态存储结构转化为方法区的运行时的数据结构
3) 在Java堆中生成一个代表这个类的java.lang.Class对象,作为这些数据在方法区中的访问入口此时运行时数据区有哪些数据:
- 方法区: 类信息、静态变量、常量
- 堆:代表被加载类的java.lang.Class对象
2.2 链接(Link)
2.2.1 验证(Verify)
文件格式
a. 是否以16进制CAFEBABY开头
b. 版本号是否正确元数据验证(Java语法校验)
a. 是否有父类
b. 是否继承了final类
c. 非抽象类是否实现了所有抽象方法字节码验证
a. 运行检查
b. 栈数据类型和操作码操作参数是否吻合
c. 跳转指令执行合理的位置符号引用验证
a. 常量池中描述类是否存在
b. 访问的方法或者字段是否存在 且 具有足够的权限
2.2.2 准备(Prepare)
为类的静态变量分配内存,并将其初始化为默认值
这里不包含final 修改的static, 因为final在编译时就会分配
2.2.3 解析(Resolve)
把类中的符号引用转为直接引用
2.3 初始化(Initailize)
初始化阶段是执行类构造器Class.init()方法的过程。