本篇文章讲述虚拟机如何加载Class文件和Class文件中的信息进入到虚拟机后会发生什么变化
1.类加载的时机
类被加载到虚拟机的内存中,他的整个生命周期包含了:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸载(Unloading)七个阶段,其中验证、准备和解析三个部分称为链接(Linking)。
对于什么阶段开始类加载的第一个阶段:加载,在虚拟机的规范中没有约束,但是对于初始化阶段,虚拟机则严格对四种情况进行了要求必须对类进行初始化
1.遇到new、getstatic、putstatic或者invokestatic这四条字节码指令的时候(场景:即使用new关键字实例化对象的时候,读取或者设置一个类的静态字段的时候,以及调用一个静态的方法的时候)
2.使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要触发其初始化
3.当初始化一个类的时候,如果一个类的父类还没有进行初始化,则要先触发父类的初始化。
4.当虚拟机启动的时候,虚拟机会先初始化包含main方法的那个主类
比如:在A类中引用B类中的静态字符串常量b,在编译的时候,对常量B.b的引用实际都被转化为A类对自身的常量池的引用了,两个类在编译成Class之后就不存在任何联系了。
接口的加载:编译器会为接口生成“<clinit>()”类构造器,用于初始化接口的成员变量,接口和类的真正区别是上面的3,在一个接口初始化的时候,并不会要求其父接口全部都初始化,只有真正用到父接口的时候(如引用接口中定义的常量)才会初始化。
类加载的过程
就上面的加载~初始化五个阶段
1.加载阶段 :1)通过类的全限定名获取定义此类的二进制字节流 2)将这个字节流的静态存储结构转化为方法区的运行时数据结构 3)在堆中生成java.lang.Class对象,作为方法区的访问入口
2.验证阶段:主要是确保Class文件的字节流包含的信息符合要求虚拟机的要求,不会危害计算机(具体过程很复杂)
3.准备阶段:正式为类变量分配内存并设置类变量的初始值的阶段,这些内存都在方法区分配,需要强调的是,这里分配的内存仅包括类变量,不包括实例变量,实例变量将会在对象的实例化时一起分配到Java堆中,这里说的初始值指的是类变量的零值,例如 public static int a = 56,在准备阶段时,a=0.其赋值是在类的构造器的<clinit>()的方法之中,赋值阶段将会在初始化阶段才会被执行。如果是public static final int a = 56 在准备阶段就是a = 56了。