字节码验证。
符号引用验证。
文件格式验证
这一阶段可能会包含下面这些验证点:
魔数是否以 0xCAFEBABE 开头。
主、次版本号是否在当前 Java 虚拟机接受范围之内。
常亮池的常量中是否有不支持的常量类型。
指向常量的各种索引值中是否有指向不存在的常量或不符合类型的常量。
CONSTANT_Utf8_info 型的常量中是否有不符合 UTF8 编码的数据。
Class 文件中各个部分及文件本身是否有被删除的或附加的其他信息。
实际上验证点远远不止有这些,上面这些只是从 HotSpot 源码中摘抄的一小段内容。
元数据验证
这一阶段主要是对字节码描述的信息进行语义分析,以确保描述的信息符合《Java 语言规范》,验证点
包括
验证的类是否有父类(除了 Object 类之外,所有的类都应该有父类)。
要验证类的父类是否继承了不允许继承的类。
如果这个类不是抽象类,那么这个类是否实现了父类或者接口中要求的所有方法。
是否覆盖了 final 字段,是否出现了不符合规定的重载等。
需要记住这一阶段只是对《Java 语言规范》的验证。
字节码验证
字节码验证阶段是最复杂的一个阶段,这个阶段主要是确定程序语意是否合法、是否是符合逻辑的。这
个阶段主要是对类的方法体(Class 文件中的 Code 属性)进行校验分析。这部分验证包括
确保操作数栈的数据类型和实际执行时的数据类型是否一致。
保证任何跳转指令不会跳出到方法体外的字节码指令上。
保证方法体中的类型转换是有效的,例如可以把一个子类对象赋值给父类数据类型,但是不能把父
类数据类型赋值给子类等诸如此不安全的类型转换。
其他验证。
如果没有通过字节码验证,就说明验证出问题。但是不一定通过了字节码验证,就能保证程序是安全
的。
符号引用验证
最后一个阶段的校验行为发生在虚拟机将符号引用转换为直接引用的时候,这个转化将在连接的第三个
阶段,即解析阶段中发生。符号引用验证可以看作是对类自身以外的各类信息进行匹配性校验,这个验
证主要包括
符号引用中的字符串全限定名是否能找到对应的类。
指定类中是否存在符合方法的字段描述符以及简单名称所描述的方法和字段。
符号引用的类、字段方法的可访问性是否可被当前类所访问。
其他验证。
这一阶段主要是确保解析行为能否正常执行,如果无法通过符号引用验证,就会出现类似
IllegalAccessError 、 NoSuchFieldError 、 NoSuchMethodError 等错误。
验证阶段对于虚拟机来说非常重要,如果能通过验证,就说明你的程序在运行时不会产生任何影响。