1、通过一个类的全限定名来获取定义此类的二进制字节流;
2、将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;
3、在java堆中生成一个代表这个类的java.lang.Class对象,作为访问入口;
这里未限定获取二进制流的方式,可以通过各种途径得到,包括jar,war等压缩包、网络、运行时生成(动态代理)、数据库中...等
加载->验证->准备->(解析->初始化)->使用->卸载
验证就不说了...
准备:这个阶段正式的为类变量分配内存,并设置初始值,内存将分配在方法区中;
必须强调的是这个阶段分配的是类的变量(static),不是实例的变量(分配在堆中);
public static int value =123;
这个阶段分配后value = 0;而不是123;这个阶段尚未执行任何java方法。而把value赋值为123的指令putstatic指令是程序被编译后,存放于类构造器<clinit>()方法中(在初始化阶段,并非是实例构造器(构造函数));然而:
public static final int value = 123;将会在这个阶段设为123(先为0然后是123);
解析:
解析的过程是虚拟机讲常量池内的符号引用替换为直接引用的过程;
触发初始化场景:
1、new关键字
2、使用java.lang.reflect,反射调用;
3、main函数,包含main的类;
4、子类被初始化;
不触发初始化的场景:
1、调用的是父类的静态域;
2、生命某个类的数组,不会触发某个类的初始化;
3、调用某个类的静态字段不会触发当前类的初始化;
参考:《深入理解java虚拟机》