类加载概述

(1)类的加载方式:

方式一:命令行启动应用时,由JVM初始化加载
方式二:通过Class.forName()方法动态加载(默认会执行初始化块,但如果指定ClassLoader,初始化时不执行静态块)
方式三:通过ClassLoader.loadClass()方法动态加载(不会执行初始化块)

(2)类加载机制

虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成能被虚拟机直接使用的Java类型。

(3)类加载时机

类加载概述_第1张图片
Paste_Image.png

注意:

1.顺序问题:

加载、验证、准备、初始化和卸载的顺序是确定的,解析阶段不一定,在某些情况下可以初始化后开始,从而支持Java语言的运行时绑定(动态绑定或者晚期绑定)

2.初始化阶段有且仅有5种情况(主动引用):

  • 遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,若类没有进行初始化,先触发其初始化(对应的场景:使用new关键字实例化对象,读取或设置一个类的静态字段,以及调用一个类的静态方法);
  • 使用java.lang.reflect包的方法对类的进行反射调用时,若没有对类初始化;
  • 初始化一个类时,发现父类还未初始化,先触发父类的初始化;
  • 当虚拟机启动时,用户需指定一个要执行的主类,虚拟机先初始化这个主类;
  • 当使用jdk1.7动态语言支持时,若一个java.lang.invoke.MethodHandle实例最后的解析结果是REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,且这个方法句柄对应的类没有进行初始化过,则先触发初始化。
    总结:5种情况都是对一个类进行主动引用:遇到四种指令、反射调用、父类未初始化、用户指定的主类初始化、jdk1.7中动态调用解析结果的方法句柄)

反例:被动引用不会触发初始化:

  • 通过子类引用父类的静态字段,不会导致子类初始化;(只会触发父类的初始化)
  • 通过数组定义来引用类,不会触发此类的初始化;
  • 常量在编译阶段会存入调用类的常量池中,本质上并没有直接引用到定义常量的类,不会触发定义常量的类的初始化;

3.接口的加载过程:

与类加载过程稍有不同,接口中不能使用static{}语句块,但编译器仍然会为接口生成“()”类构造器,用于初始化接口中成员变量。
真正的区别是:初始化一个类时,接口不要求其父接口全部完成初始化,只有真正使用父接口的时候才会初始化。
类从被加载到虚拟机内存中开始,到卸载出内存为止,类的生命周期:加载——验证——准备——解析——初始化——使用——卸载。7个阶段。
连接:是验证——准备——解析三个部分

(4)类加载的过程

1.加载2.验证3.准备4.解析5.初始化

(5)三大类加载器:

启动类加载器——扩展类加载器——应用程序类加载器

你可能感兴趣的:(类加载概述)