Java 中的类何时被加载器加载
Java 程序中的 .class 文件会在以下 2 种情况下被 ClassLoader 主动加载到内存中:
1.调用类构造器
2.调用类中的静态(static)变量或者静态方法
Java 中 ClassLoader
JVM 中自带 3 个类加载器:
启动类加载器 BootstrapClassLoader
扩展类加载器 ExtClassLoader (JDK 1.9 之后,改名为 PlatformClassLoader)
系统加载器 APPClassLoader
双亲委派模式
所谓双亲委派模式就是,当类加载器收到加载类或资源的请求时,通常都是先委托给父类加载器加载,也就是说,只有当父类加载器找不到指定类或资源时,自身才会执行实际的类加载过程。
具体实现代码是在 ClassLoader.java 中的 loadClass 方法中
判断该 Class 是否已加载,如果已加载,则直接将该 Class 返回。
如果该 Class 没有被加载过,则判断 parent 是否为空,如果不为空则将加载的任务委托给parent。
如果 parent == null,则直接调用 BootstrapClassLoader 加载该类。
如果 parent 或者 BootstrapClassLoader 都没有加载成功,则调用当前 ClassLoader 的 findClass 方法继续尝试加载。
Test test = new Test(); 默认情况下,JVM 首先使用 AppClassLoader 去加载 Test 类。
AppClassLoader 将加载的任务委派给它的父类加载器(parent)—ExtClassLoader。
ExtClassLoader 的 parent 为 null,所以直接将加载任务委派给 BootstrapClassLoader。
BootstrapClassLoader 在 jdk/lib 目录下无法找到 Test 类,因此返回的 Class 为 null。
因为 parent 和 BootstrapClassLoader 都没有成功加载 Test 类,所以AppClassLoader会调用自身的 findClass 方法来加载 Test。
Java 类的加载过程是什么 主要分 3 大步:装载、链接、初始化。其中链接中又包含验证、准备、解析 3 小步。
装载:指查找字节流,并根据此字节流创建类的过程。装载过程成功的标志就是在方法区中成功创建了类所对应的 Class 对象。
链接:指验证创建的类,并将其解析到 JVM 中使之能够被 JVM 执行。
初始化:则是将标记为 static 的字段进行赋值,并且执行 static 标记的代码语句 。
验证:核验字节信息是符合 Java 虚拟机规范;
准备:创建类或接口中的静态变量并初始化,侧重分配所需要的内存空间(与初始化阶段区分开);
解析:替换常量池中的符号引用为直接引用,类、接口、方法和字段等各个方面的解析等