类的装载就是把class文件加载到虚拟机的运行数据区,虚拟机的类加载器负责把class文件加载到运行数据区。
类加载器在装载class文件的过程中,会把class文件转换为方法区的内部数据结构,并创建一个表示该类型的java.lang.Class类的实例,Class类的实例存储到数据运行区的堆。
创建Class类的实例后,类加载器会验证加载的类是否符合Java语义规范,并且它不会对虚拟机造成破坏或者导致虚拟机崩溃。类加载器也会检查该类的所有父类是否都已经被加载。
类装载成功后,虚拟机会为类变量分配内存,设置默认初始值,同时会为类方法构建方法表,该方法表存储指向每一个方法(包括从父类继承的方法)的内存地址,当虚拟机需要调用类方法时,直接从方法表中查找方法的内存地址。类变量、方法和方法表都存储在虚拟机运行数据区的方法区。
类装载的最后一个步骤就是初始化,也就是为类变量赋予正确的初始值,正确的初始值是程序员在编写代码时赋予变量的值,不是前面设置的默认初始值。在Java语言中,变量正确的初始值是通过变量初始化语句或者静态初始化语句给出的。所有的类变量初始化语句和静态初始化语句都被Java编译器收集在一起,并放置到一个名称为“<clinit>”方法中,这个方法在已编译好的class文件中,虚拟机在初始化类的过程中,会调用这个方法。
初始化一个类包含下面两个步骤:
(1) 如果该类存在父类,且父类没有被初始化时,先初始化父类;
(2) 如果存在一个类初始化方法,就执行这个方法。
当初始化一个父类时,也需要包含上面的两个步骤,因此顶层的Object类最先被初始化,然后是类的继承链上所有的类。
当一个类的变量使用static和final修饰符时,虚拟机会把该类变量放置到常量池中,常量池是方法区分出来的一块内存区域,主要用于存放类的字面常量(如数值)、被static和final修饰的类变量、符号引用。