类加载器

实现类的加载过程的代码被称为类加载器(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  阅读(27)  评论(0)    收藏  举报