JAVA类加载机制详细介绍

目录

 

类的生命周期 

类加载的过程

阶段1:加载

阶段2:验证

阶段3:准备

阶段4:解析

阶段5:初始化

方法的几个注意事项()>


类的生命周期 

 


类加载的过程

阶段1:加载

加载是类加载的第一个阶段,需要完成三件事情:

  • 通过一个类的全限定名来获取定义该类的二进制字节流。
  • 将这个字节流的表现的“静态存储结构”转化为方法区的运行时数据结构。
  • 在内存中生成一个Class对象,作为这个类的类对象,也是这个类的各种数据的访问入口。

可以理解为加载阶段的任务就是将Class文件中的类  加载进方法区中。

方法区(Java内存区域介绍)


阶段2:验证

验证是为了确保加载进来的类信息符合虚拟机的要求。

验证分为四种:

  • 文件格式验证
  • 元数据验证
  • 字节码验证
  • 符号引用验证

由于不是特别重要,就不展开了,有兴趣了解可以百度。


阶段3:准备

准备阶段是正式为类变量分配内存并初始化的阶段,这里的类变量仅仅是类中定义的static变量!非static变量是在实例对象的时候随对象一起分配在堆中!

所有的static变量将会被初始化为零值。

public static int a=123;

上述代码中,在准备阶段,a会被初始化为0,然后在接下来的类初始化阶段才会赋值为123。


阶段4:解析

解析阶段是将常量池中的符号引用替换为直接引用的过程。不同虚拟机实现可以根据需要判断到底是在类被加载器加载的时候对常量池的符号引用进行解析(也就是初始化之前),还是等到一个符号引用被使用之前进行解析(也就是在初始化之后)。

如果一个符号引用进行多次解析请求,虚拟机可以对第一次解析的结果进行缓存(在运行时常量池中记录引用,并把常量标识为一解析状态),这样就避免了一个符号引用的多次解析。但是invokedynamic指令除外,因为invokedynamic指令执行时,之前缓存的解析结果不一定有效,所以调用invokedynamic指令时需要重新解析。

解析动作主要针对的是类或者接口、字段、类方法、方法类型、方法句柄和调用点限定符7类符号引用。


阶段5:初始化

初始化阶段是类加载过程的最后一步,这一步才真正开始执行类中定义的Java程序代码。

初始化阶段是执行类构造器<clinit()>方法的过程。

<clinit()>方法是由编译器自动按顺序收集类变量赋值操作和静态初始化块(static{})中的语句合并产生的。

关于静态初始化块的介绍请看我的另一篇博文

Java中的静态初始化和非静态初始化

 

<clinit()>方法的几个注意事项

  • <clinit()>方法和类的构造函数不一样,不需要显式调用父类构造器,虚拟机会保证在<clinit()>方法执行前其父类的<clinit()>方法已经执行完毕。
  • <clinit()>方法不是必须的,如果一个类中没有类变量的赋值操作和静态初始化块,则虚拟机不会为其生成<clinit()>方法。
  • 接口或者类的<clinit()>方法不需要先执行父接口的<clinit()>方法,只有当父接口中的变量或者方法被使用时,才会执行父接口的<clinit()>方法。
  • <clinit()>方法是同步的。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章