类加载机制
加载
- 加载前虚拟机需要完成的3件事情
- 通过一个类的全限定名来获取定义此类的二进制字节流。
- 通过这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
- 在内存中生成一个代表这个类的
java.lang.Class
对象,作为方法区这个类的各种数据的访问入口。
- 加载完成后,按照虚拟机所需的格式将二进制字节流存储在方法区中。
- 加载与连接的部分内容一般都是交替进行的。
验证(非必须步骤,可通过参数-Xverify:none
来关闭大部分类的验证措施)
- 验证
Class
文件的字节流中进包含的信息是否符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
文件格式验证(该阶段主要基于二进制字节流进行验证。只有通过验证后,字节流才会进入方法区进行存储。)
- 是否以魔数
0xCAFEBABE
开头。 - 主、次版本号是否在当前虚拟机处理范围之内。
- 常量池中的常量是否有不被支持的常量类型(检查常量
tag
标志) - 指向常量的各种索引值是否有指向不存在的常量或不符合类型的常量。
CONSTANT_Utf8_info
型的常量中是否有不符合UTF8
编码的数据。Class
文件中各个部分及文件本身是否有被删除的或附加的其他信息。
元数据验证(保证不存在不符合Java语言规范的元数据信息)
- 这个类是否有父类
- 这个类是否继承了不许云被继承的类
- 如果这个类不是抽象类,是否实现了其父类或接口之中要求实现的所有方法。
- 类中的字段、方法是否与父类产生矛盾。(例如是否覆盖了父类的
final
字段等)。
字节码验证(对类的方法体进行校验分析,保证被校验类的方法在运行时不会做出危害虚拟机安全的事件。)
- 保证任意时刻操作数栈的数据类型与指令代码序列都能配合工作。
- 保证跳转指令不会跳转到方法体以外的字节码指令上。
- 保证方法体中的类型转换是有效的。
符号引用验证(保证之后的解析能正常执行)
- 符号引用中通过字符串描述的全限定名是否能找到对应的类。
- 在指定类中是否存在符合方法的字段描述符以及简单名称所描述的方法和字段。
- 符号引用中的类、字段、方法的方文星是否可以被当前类访问。
准备
- 为类变量(被
static
修饰的变量)分配内存并设置类变量初始值的阶段 - 如:
public static int value = 123;
,在准备阶段是0而不是123,赋值123是在初始化阶段进行的。
解析(虚拟机将常量池内的符号引用替换为直接引用的过程)
- 类或接口的解析
- 字段解析
- 类方法解析
- 接口方法解析
初始化
- 遇到
new、getstatic、putstatic、invokestatic
这4条字节码指令是执行初始化。(使用new
关键字实例化对象的时候、读取或设置一个类的静态字段(被final
修饰、已在编译器把结果放入常量池的静态字段除外)的时候,以及调用一个类的静态方法时。) - 使用
java.lang.reflect
包的方法对类进行反射调用的时候。 - 当初始化一个类时,其父类还没有初始化的时候。
- 虚拟机启动时,执行主类(
main()方法
) - 使用
JDK1.7
的动态语言支持时。
评论区