类的加载流程主要分为加载,连接,卸载,使用,初始化,其中连接还可以分为验证,准备,解析。
但实际上这些流程都是按顺序穿插进行的,例如加载过程中,实际上也会进行字节码的验证等等。
所以实际流程应该为
- 通过类的全限定名获取到类的字节流
- 加载的时候验证文件的格式,确保class文件中的信息集合符合java虚拟机规范 主要验证class文件结构是否正确,例如是否以魔数开头,主次版本号是否被虚拟机识别,如java9不支持jdk8之前的java版本,常量池的索引值是否指向不存在的常量或不符合类型的常量等
- 将静态结构转换为运行时结构,也就是加载到方法区中,方法区主要存储各种类型信息
- 元数据验证,主要对对象进行语义检查,基本上ide已经进行了该校验
- 字节码验证,这个也是验证过程中最复杂的验证,主要是对方法表中的数据进行校验,例如类型转换操作栈中放置了int属性,使用时却按long类型使用等,jdk6后将这过提前到编译期进行,并形成StackMapTable属性,这是字节码验证时,只需要遍历StackMapTable中是否有问题即可
- 符号应用验证,校验符号引用中的地址能否找到类,引用的类,字段是否可以被当前类访问(private、protected、public)等
- 全部验证通过后,才会真的形成一个class对象,并放置在堆内存中,且各种类型的数据的访问地址会直接指向方法区来查询对应的属性
- 形成对象后,会对类的一些静态变量进行内存分配,也就是赋值初值,这里进行分配的只是类变量例如public static int value = 123,且此时赋值的时初始值也就是零值,因为这是还没有调用类的方法也就是构造方法,所以还未进行变量真正的赋值操作 最后再将类的常量池中所有的符号引用转化为直接引用,也就是对字段,类,接口等信息进行解析,直接指向对应的目标的句柄,虚拟机在解析常量引用的时候,会将以解析完的常量进行标识,从而避免解析动作的重复执行
至此类的整体加载流程就完毕了