类加载器和双亲委派模型

类加载器

JVM 中内置了三个重要的 ClassLoader,除了 BootstrapClassLoader 其他类加载器均由 Java 实现且全部继承自java.lang.ClassLoader:

  • BootstrapClassLoader(启动类加载器) :最顶层的加载类,由C++实现,负责加载 %JAVA_HOME%/lib目录下的jar包和类或者或被 -Xbootclasspath参数指定的路径中的所有类。

  • ExtensionClassLoader(扩展类加载器) :主要负责加载目录 %JRE_HOME%/lib/ext 目录下的jar包和类,或被 java.ext.dirs 系统变量所指定的路径下的jar包。

  • AppClassLoader(应用程序类加载器) :面向我们用户的加载器,负责加载当前应用classpath下的所有jar包和类。

类加载器和双亲委派模型

双亲委派模型

双亲委派模型介绍

  • 其实这个双亲翻译的容易让别人误解,我们一般理解的双亲都是父母,这里的双亲更多地表达的是“父母这一辈”的人而已,类加载器之间的“父子”关系也不是通过继承来体现的,是由“优先级”来决定。

  • 每个类都有对应类加载器。系统中的 ClassLoder 默认使用 双亲委派模型 。即在类加载的时候,系统会首先判断当前类是否被加载过。已经被加载的类会直接返回,否则才会尝试加载。

  • 加载的时候:首先会把该请求委派该父类加载器的 loadClass() 处理,因此所有的请求最终都应该传送到顶层的启动类加载器 BootstrapClassLoader 中。当父类加载器无法处理时,才由自己来处理。

双亲委派模型的优点

  • 优点1:

    双亲委派模型保证了Java程序的稳定运行,实现简单

  • 优点2:

    可以避免类的重复加载,保证使用不同的类加载器,最终得到的都是同样的一个object对象,比如我们编写一个称为 java.lang.Object 类的话,那么程序运行的时候,系统就会出现多个不同的 Object 类。

不想用双亲委派模型怎么办——怎么打破双亲委派机制?

为了避免双亲委托机制,我们可以自己定义一个类加载器,然后重载 loadClass() 即可。

今天在看面经的时候看到一个问题,怎么打破双亲委派机制,觉得很有意思,一般来说面试官关心的都是双亲委派机制的三个特性或者说这个机制的作用,第一次看到这样问的,于是来总结一下打破这个机制的方法:

1:自己写一个类加载器

2:重写loadclass方法

3:重写findclass方法

这里最主要的是重写loadclass方法,因为双亲委派机制的实现都是通过这个方法实现的,先找附加在其进行加载,如果父加载器无法加载再由自己来进行加载,源码里会直接找到根加载器,重写了这个方法以后就能自己定义加载的方式了

如何自定义类加载器?

除了 BootstrapClassLoader 其他类加载器均由 Java 实现且全部继承自java.lang.ClassLoader。如果我们要自定义自己的类加载器,很明显需要继承 ClassLoader。