类加载
# 类的生命周期
- 加载
- 链接
- 初始化
- 使用
- 卸载
# 类加载过程
加载
由类加载器完成,每个Java类都有一个引用指向加载它的ClassLoader;
- 获取此类的二进制字节流;
- 将字节流中的静态存储结构(一些字节)转换为方法区的运行时数据结构;
- 在内存生成一个代表该类的Class对象;
链接
验证;
确保Class文件的字节流符合规范;
准备
正式为类变量分配内存并设置类变量初始值;
类变量为static修饰的变量,类变量所使用的内存在方法去中分配;
解析
将运行时常量池内的符号引用替换为直接引用;
初始化
类初始化的6种情况:
- new 一个类,读取一个静态字段(未被final修饰),调用一个类的静态方法;
- 反射调用,如果类没有初始化,需要初始化;
- 初始化一个类,父类没有初始化,先初始化父类;
- 虚拟机启动,初始化包含main方法的类;
MethodHandle
和VarHandle
可以看作是轻量级的反射调用机制,而要想使用这 2 个调用,就必须先使用findStaticVarHandle
来初始化要调用的类;- 当一个接口中定义了 JDK8 新加入的默认方法(被 default 关键字修饰的接口方法)时,如果有这个接口的实现类发生了初始化,那该接口要在其之前被初始化;
# 类加载器
每个 Java 类都有一个引用指向加载它的
ClassLoader
;数组类不是通过
ClassLoader
创建的(数组类没有对应的二进制字节流),是由 JVM 直接生成的;
加载规则?
JVM 启动的时候,并不会一次性加载所有的类,而是根据需要去动态加载。也就是说,大部分类在具体用到的时候才会去加载;
类加载器?
BootstrapClassLoader(启动类加载器):加载 JDK 内部的核心类库;
ExtensionClassLoader(扩展类加载器):主要负责加载
%JRE_HOME%/lib/ext
目录下的 jar 包和类以及被java.ext.dirs
系统变量所指定的路径下的所有类;AppClassLoader(应用程序类加载器):面向我们用户的加载器,负责加载当前应用 classpath 下的所有 jar 包和类;
双亲委派模型?
ClassLoader类使用委托模型来搜索加载类;
除了顶层启动类加载器,每个类加载器都有自己的父类加载器,ClassLoader实例会在试图亲自加载类之前,将加载类的任务委托给父类加载器;
打破双亲委派模型?
重写loadClass()方法;