把描述类的数据从Class文件加载到内存,并且对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型。
类加载生命周期
- loading, (加载), bring binary form of a type into JVM
- linking, (连接), incorporating the binary type data into the JVM runtime state
- Verification, 验证, ensure type is properly formed and fit
- Preparation, 准备, allocating the memory needed by the type
- Resolution, 解析, transforming symbolic reference in constant pool into direct reference
Initialization, 初始化, the class variabes are given their proper initial value
Using, 使用
- Unloading, 卸载
lifecycle = loading , linking, initialize
linking(连接) = 验证 + 准备 + 解析
加载
类的加载时机(虚拟机没有进行规定,由各虚拟机自己把握)
- 找数据: 通过一个类的全限定名来获取该类的二进制流
- 转换:二进制流的静态存储结构 ——> 运行时的数据结构(在方法区中,由虚拟机自己实现)
- 内存java.lang.class对象,作为入口
方法区
- 存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
- Non-Heap
- 永久代Permanent Generation
连接
连接 = 验证 + 准备 + 解析
验证
为了确保class文件的字节流包含的信息符合当前虚拟机要求,不会危害虚拟机自身安全
纯粹的java代码无法做到
- 文件格式验证
- 是否以魔数开头
- 版本号
- 元数据验证
- 字节码验证
- 符号引用验证
- make sure the reference exist and have access permission
准备
no java code execute
为类变量分配内存并且设置初始值, 仅仅是static变量
- set to default 0
- allocate the memory for improve the performance(扩充方法区)
解析
将常量池的符号引用替换为直接引用
locating classes, interfaces, fields, methods from constant pool, and replace to direct reference.
- 通过全限定名是否能找到对应的类
- 是否存在符合方法的字段描述符以及简单名称所描述的方法和字段
- 类、字段、方法访问性等等
初始化
setting the class variables to the proper initial value
- via a class variable initializer
static int size = 3 * (int) (Math.random() * 5.0);
- via static initializer
static int size;
// This is the static initializer
static {
size = 3 * (int) (Math.random() * 5.0);
}
类的初始化时机(虚拟机规范有严格的规定),initialize on first active used
- new, getstatic, putstatic, invokestatic这四条字节码指令(new对象, 读取设置类的静态字段,调用类的静态方法)
- 对类进行反射调用的时候
- 初始化子类,要初始化父类
- 虚拟机启动时,需要初始化主类(Main方法)
- 使用动态语言支持时,java.lang.invoke.MethodHandler实例最后解析结果的方法句柄所对应的类没有进初始化
- REF_getStatic
- REF_putStatic
- REF_invokeStatic
注意,初始化并不代表着调用构造函数
class initialize method
all class variable initializer and static initializer woudl be collected by compiler and place into a speicial method call class intialization method “<clinit”
two steps
- 初始化父类(如果有父类)
- 执行”<clinit”(如果有)
- 没有类变量则不会有”<clinit”函数
- 有类变量但是没有initializer,则不会有”<clinit”函数
- 有类变量有initializer,但是使用compile-time constant expression初始化,也不会有”<clinit”函数