运行前的准备工作
在javac编译成.class文件中的字节流后,在运行时jvm要将.class文件加载到JVM中,并且进行相应的处理便于之后的运行。
整个加载到运行中的步骤如下
1.加载 2.连接(验证,准备,解析)3.初始化 4.使用 5.卸载
可以看到初始化之前需要完成loading和linking的过程,初始化的时机在虚拟机规范中有明确的规定
在虚拟机启动时会先对main所在的主类进行加载/连接/初始化
其他类的初始化发生在:
1.使用new指令创造一个类的对象时
2.使用getstatic,putstatic或invokestatic对静态字段进行读写操作,以及调用一个类的静态方法时
3.初始化该类时,其父类还没有初始化,先初始化该类的父类
4.MethodHandle?
以上几种情况称为对一个类进行主动引用,以上操作会引发JVM对类的初始化,所以初始化之前的准备工作(加载,连接)应该在之前完成
加载
类加载过程
非数组类:
1.jvm通过类的全限定名获取此类的二进制流(classloader完成的工作,)
2.将字节流转化为方法区该类的数据结构
3.生成class对象作为方法区该类数据的访问入口
数组类的加载:
数组类本身不是由类加载器加载,而是由虚拟机直接加载的
数组类的标识规则如下
reference的数组:数组将在加载该组件类型的类加载器的类名称空间被标识
primitive type的数组:与引导类加载器关联
ClassLoader与Class
每个类必须与类加载器一起确定唯一性,两者共同标识一个类
ClassLoader决定了用户获取需要的类的方式
编译后的.class文件,经过不同的ClassLoader加载到JVM,在方法区中产生两个不同的类
Class类中的equals(),isInstance()都对ClassLoader进行比较
验证
验证在加载后进行,JVM验证加载到方法区的Class字节流是否符合当前虚拟机的要求
准备
static与static final变量的赋值时机
static final变量在准备阶段就已经完成赋值,该字段在编译时会生成ConstantValue的属性表,准备阶段jvm通过读取方法区中该字段表的属性表给静态常量赋值
static变量作为类变量,在类初始化时通过<cinit>函数赋值,实例变量通过<init>进行赋值