类加载器
实现类的加载过程的代码被称为类加载器(Class Loader)
对于任意一个类,都必须由加载它的类加载器和这个类本身一起共同确立其在Java虚拟机中唯一性,每个类加载器都拥有一个独立的类名称空间。即比较两个类是否“相等”,只有在这两个类是由同一个类加载器加载的前提下才有意义,否则,即使这两个类来源于同一个Class文件,被同一个Java虚拟机加载,只要它们的类加载器不同,那么这两个类必定不相等。
这里所说的相等,包括代表类的Class对象的equals()方法,IsAssignableFrom()方法、isInstance()方法的返回结果,也包括了使用instanceof关键字做对象所属关系判定等各种情况。
双亲委派模型--jdk8及之前版本
在JVM角度看,只存在两种不同的类加载器:一种是启动类加载器(Bootstrap ClassLoader),这个类加载器使用C++实现,是虚拟机自身的一部分;另一种是其他所有类加载器,这些加载器是由Java语言实现,独立存在于JVM外部,并全部继承抽象类java.lang.ClassLoader。

双亲委派模型的工作过程:如果一个类加载器收到类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每个层次的类加载器都是如此,因此所有的加载请求最终都应该传递到最顶层的启动类加载器中,只有当父加载器反馈自己无法完成加载请求(它的搜索范围中没有找到所需的类),子类加载器才会尝试自己去完成加载。
先检查请求加载的类是否已经被加载过,若没有则调用类加载器加载,若父加载器为空,则默认使用启动类加载器作为父类加载器,若父加载器加载失败,才会尝试自己加载。
设计目的:带有优先级的层次关系,比如类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,从而保持了统一性。

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

JDK9+版本的双亲委派模型

JDK9虽然仍维持着三层类加载器和双亲委派模型的架构,但类加载的委派关系发生了变动。
当平台及应用程序类加载器收到类加载请求,在委派给父加载器前,会先判断该类是否能够归属到某一个系统模块中,如果可以找到这样的归属关系,就优先委派给负责该模块的加载器完成加载。只有当无法找到模块归属时,才会继续遵循双亲委派模型。
|
|
|
|
|---|---|---|
|
|
|
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 |
|
|
|
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 |
|
|
|
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* |

浙公网安备 33010602011771号