加载
1、通过1类的全路径名来获取定义该类的二进制字节流
2、加载常量到方法区中的常量池
3、在方法区生成一个这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口
**是不是所有的对象都会加载到堆中?**答案是NO。
虚拟机将类加载到方法区的时候,就会在方法区生成一个Java.lang.Class的对象
加载文件来源:ZIP包、WAR包、JSP动态生成、Proxy、从数据库中读取(这种场景相对少)
验证
验证是连接阶段的第一步,这一阶段是确保Class文件中的字节流包含的信息符合当前虚拟机的要求
1、验证Class结构的正确性,如果错误,会抛Java.lang.VerifyError异常
1)验证魔数:前4个字节(0xCAFEBABE)
2)主次版本号是否在当前虚拟机的范围内
3)常量池中的常量是否有不被支持的类型。
4)Class文件的结构是否齐全,是否有被删减的地方
2、元数据验证(保证元数据信息进行语义校验。验证是否符合Java规范)
1)这个类是否有父类(除了Object外,所有的类都应该有父类)
2)这个类是否继承了不被允许的类(被final修饰的类)
3)这个类不是抽象,是否实现了其抽象父类或接口要求的所有方法
4)类中的字段、方法是否与父类产生矛盾
(例如覆盖了父类的final字段。或则出现不符合规则的方法重载,例如方法参数都一致,返回类型不同)
3、字节码验证(最复杂的)
1)保证操作数栈的数据类型与指令代码都能够配合工作
2)这样的情况:在操作栈放了一个int的数据,使用的时候却是用long来使用
3)保证跳转指令不会跳转到方法以外的字节码指令上
4)保证方法体内的转换是有效的。
例如:把一个子对象赋值给父对象,是有效的。但是把一个父对象赋值给子对象是错误的。
4、符号引用验证(为连接的第三阶段:解析,做准备。主要是校验访问性)
1)符号引用能否通过字符串的全路径名是否能找到该类
2)符号引用能否通过符合该引用的方法和字段
3)符号引用中的类、字段、方法的访问性(public,protected,private,default)
是否可被当前类访问
符号引用的验证主要是为了确保解析阶段能否正常的运行。如果无法通过符号引用验证
则会报错:java.lang.incompatibleClassChangeError的子类:
java.lang.illegalAccessError,java.lang.NosuchFieldError,java.lang.NoSuchMethodError.
准备
准备阶段是正式为类变量分配内存并设置类初始值的阶段。
只为static 变量设置初始值。实例变量(即对象变量,引用变量,非static 变量)将会在对象实例化的时候加载
为static变量设置初始值
public class Test{
public static int i=123;
}
准备阶段,变量 i 的值是 0.
把变量 i 赋值为 123 是在初始化的时候,才会执行
解析
解析是将常量池中的符号引用转换直接引用的过程,不止解析1次
符号引用以CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Mehodref_info 等类型的常量出现
符号引用与内存布局无关。直接引用与内存布局有关