1. JVM可以加载任何符合JVM指定规范的Class文件,并不限定是从什么语言或是形式得来的。但是,JVM为了自身的安全性,防止恶意代码的攻击,会对Class文件进行验证,主要分为以下几步:
  1. 文件格式的验证:是否符合Class文件的规范,以及能够被当前版本的虚拟机处理。
  1. 是否以0xCAFEBABE开头。
  2. 主、次版本是否在当前虚拟机处理的范围之内。
  3. 常量池的常量是否有不支持的常量类型。
    等等,主要的目的是保证输入的字节流能够正确的解析并存储于方法区之内,格式上符合一个java类型信息的要求。只有通过这个阶段的验证,虚拟机才会让字节流进入到方法区中进行存储,后面的验证都是直接操作在方法区之上,而不是直接操作字节流。
  1. 元数据验证:对字节码描述的信息进行语义分析,以保证其描述符合java语言规范的要求。比如验证:
  1. 这个类是否有父类,java中除了Object,其它的类必须存在父类,默认为Object。
  2. 这个类是否extends了不被允许的类,如被final修饰的类。
  3. 如果这个类不是抽象类,是否实现了其父类或接口之中需要实现的所有方法。
  4. 类中的字段、方法是否与父类产生矛盾,如覆盖了父类的final字段和方法,覆盖不符合规则等等。
  1. 字节码验证:主要目的是通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。主要对方法进行验证,防止方法在运行时,不会做出对虚拟机有危害的操作。例如:
  1. 保证任意时刻操作数栈的数据类型与指令码序列都能够配合工作,不会出现类似,在操作栈放置了一个int类型的数据,使用时却按long类型来载入本地变量表中。
  2. 保证跳转指令不会跳到方法体以外的字节码指令上。
  3. 保证类型转换是有效的,例如把父类型赋值给子类型是安全的,子类型赋值给父类型就是不安全危险的。
  1. 解析:是虚拟机将常量池内的符号引用替换为直接饮用的过程。
  1. 符号引用(与虚拟机无关,不同的虚拟机翻译出来必然相同):符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要能够无歧义的定位到目标即可。符号引用的字面量形式明确定义在java虚拟机规范的Class文件中。
  2. 直接饮用(与虚拟机有关,不同的虚拟机翻译出来一般不会相同):直接引用可以是直接指向目标的指针、相对偏移量或是一个能够间接定位到目标的句柄。
  3. 字段解析:JVM对字段的搜索:
  1. 若类本身包含该字段了简单名称和字段描述都和目标相符合的字段,直接返回此字段,查找结束。
  2. 若类本身找不到,则可以找它的父类和父接口,则返回字段引用。
  3. 若是一直没有找到则抛出java.lang.NoSuchFieldError异常。