类加载器

实现类的加载过程的代码被称为类加载器(Class Loader)

对于任意一个类,都必须由加载它的类加载器和这个类本身一起共同确立其在Java虚拟机中唯一性,每个类加载器都拥有一个独立的类名称空间。即比较两个类是否“相等”,只有在这两个类是由同一个类加载器加载的前提下才有意义,否则,即使这两个类来源于同一个Class文件,被同一个Java虚拟机加载,只要它们的类加载器不同,那么这两个类必定不相等。

这里所说的相等,包括代表类的Class对象的equals()方法,IsAssignableFrom()方法、isInstance()方法的返回结果,也包括了使用instanceof关键字做对象所属关系判定等各种情况。

双亲委派模型--jdk8及之前版本

在JVM角度看,只存在两种不同的类加载器:一种是启动类加载器(Bootstrap ClassLoader),这个类加载器使用C++实现,是虚拟机自身的一部分;另一种是其他所有类加载器,这些加载器是由Java语言实现,独立存在于JVM外部,并全部继承抽象类java.lang.ClassLoader。

class-loader-parents-delegation-model

双亲委派模型的工作过程:如果一个类加载器收到类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每个层次的类加载器都是如此,因此所有的加载请求最终都应该传递到最顶层的启动类加载器中,只有当父加载器反馈自己无法完成加载请求(它的搜索范围中没有找到所需的类),子类加载器才会尝试自己去完成加载。

先检查请求加载的类是否已经被加载过,若没有则调用类加载器加载,若父加载器为空,则默认使用启动类加载器作为父类加载器,若父加载器加载失败,才会尝试自己加载。

设计目的:带有优先级的层次关系,比如类java.lang.Object,它存放在rt.jar中,无论哪个类加载器需要加载该类,最终都是委托处于模型最顶端的启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都能够保证是同一个类。

JDK9+版本的类加载机制

在JDK9发布之后,Java引入了模块化系统,导致类加载器在设计上产生了重大变革。为了适应这一变化,Java类被封装在jmod文件中,并保存在名为jmods的文件夹中。这样的结构有助于更好地管理和组织Java类,同时提高代码的可维护性和安全性。

启动类加载器

在JDK 9及之后的版本中,启动类加载器是用Java编写的,并位于jdk.internal.loader.ClassLoaders类中。

在Java中,BootClassLoader从模块中寻找要加载的字节码资源文件,这是通过继承自内置类加载器BuiltinClassLoader并实现相应的功能来实现的。

值得注意的是,启动类加载器仍然无法通过Java代码直接获取,返回值仍然是null,从而保持了统一性。

image

平台类加载器(Platform Class Loader)

在JDK 9及之后,扩展类加载器被替换为平台类加载器。这个类加载器遵循模块化方式加载字节码文件,因此它的继承关系从URLClassLoader变为了BuiltinClassLoader。BuiltinClassLoader实现了从模块中加载字节码文件的功能。平台类加载器的存在更多的是为了与老版本的设计方案兼容,自身并没有特殊的逻辑。

image

 

JDK9+版本的双亲委派模型

image

JDK9虽然仍维持着三层类加载器和双亲委派模型的架构,但类加载的委派关系发生了变动。

当平台及应用程序类加载器收到类加载请求,在委派给父加载器前,会先判断该类是否能够归属到某一个系统模块中,如果可以找到这样的归属关系,就优先委派给负责该模块的加载器完成加载。只有当无法找到模块归属时,才会继续遵循双亲委派模型。

类加载器
主要职责
代表性加载模块(部分列表)
启动类加载器​
加载 Java 运行时最核心的基础模块。
java.base(包含 java.lang, java.util等),
java.datatransfer,
java.desktop,
java.instrument,
java.logging,
java.management,
java.management.rmi,
java.naming,
java.prefs,
java.rmi,
java.security.sasl,
java.xml,
jdk.httpserver,
jdk.internal.vm.ci,
jdk.management,
jdk.management.agent,
jdk.naming.rmi,
jdk.net,
jdk.sctp,
jdk.unsupported
平台类加载器​
加载其他与平台相关的模块,取代了 JDK 8 中的扩展类加载器。
java.activation*,
java.compiler*,
java.corba*,
java.scripting,
java.se,
java.se.ee,
java.security.jgss,
java.smartcardio,
java.sql,
java.sql.rowset,
java.transaction*,
java.xml.bind*,
java.xml.crypto,
java.xml.ws*,
java.xml.ws.annotation*,
jdk.accessibility,
jdk.charsets,
jdk.crypto.cryptoki,
jdk.crypto.ec,
jdk.dynalink,
jdk.incubator.httpclient,
jdk.internal.vm.compiler*,
jdk.jsobject,
jdk.localedata,
jdk.naming.dns,
jdk.security.auth,
jdk.security.jgss,
jdk.xml.dom,
jdk.zipfs
应用程序类加载器​
加载应用级别的模块以及 classpath 上的类。
jdk.aot,
jdk.attach,
jdk.compiler,
jdk.editpad,
jdk.hotspot.agent,
jdk.internal.ed,
jdk.internal.jvmstat,
jdk.internal.le,
jdk.internal.opt,
jdk.jartool,
jdk.javadoc,
jdk.jcmd,
jdk.jconsole,
jdk.jdeps,
jdk.jdi,
jdk.jdwp.agent,
jdk.jlink,
jdk.jshell,
jdk.jstatd,
jdk.pack,
jdk.policytool,
jdk.rmic,
jdk.scripting.nashorn.shell,
jdk.xml.bind*,
jdk.xml.ws*

 

 

posted @ 2025-12-17 12:49  wang_longan  阅读(31)  评论(0)    收藏  举报