类加载优先级由双亲委派模型决定,Bootstrap ClassLoader优先级最高,Extension次之,Application最低;类加载时先委托父加载器,父无法加载时子加载器才尝试加载,确保核心类安全与类唯一性;Tomcat隔离和SPI机制等场景会打破该模型。

在Java中,类加载的优先级主要体现在类加载器的委托机制和双亲委派模型上。理解类加载优先级,关键在于搞清楚类加载器之间的层级关系以及类加载时的查找顺序。
类加载器的层次结构
Java中的类加载器分为三类,按优先级从高到低依次是:
- Bootstrap ClassLoader(启动类加载器):负责加载JVM核心类库(如rt.jar),用C++编写,是虚拟机的一部分。
- Extension ClassLoader(扩展类加载器):加载jre/lib/ext目录下的类或java.ext.dirs系统变量指定路径中的类。
- Application ClassLoader(应用程序类加载器):也叫系统类加载器,负责加载classpath中指定的类。
开发者还可以自定义类加载器,通常继承ClassLoader类,其默认父加载器就是应用类加载器。
双亲委派模型的工作流程
当一个类加载器收到类加载请求时,并不会自己立刻去加载,而是先委托给父类加载器去完成。这个过程从下往上层层委托,直到到达顶层的启动类加载器。只有当父类加载器无法完成加载(返回null),子类加载器才会尝试自己加载。
立即学习“Java免费学习笔记(深入)”;
这个机制确保了:
- 核心类库的安全性,避免用户自定义的java.lang.String等类被恶意替换。
- 类的唯一性,同一个类不会被不同类加载器重复加载,保证了类的全局唯一性。
类加载的实际优先级顺序
虽然“优先级”听起来像是谁先加载谁就高,但实际是“父优先”的原则。比如:
- 你写了一个java.lang.MyClass放在项目中,应用类加载器收到加载请求后,会先交给扩展类加载器,再交给启动类加载器。
- 启动类加载器检查rt.jar中是否有该包名下的类,发现不允许用户覆盖核心包,于是不加载。
- 请求逐层返回,最终由应用类加载器加载你写的类(但java.lang包名受限,通常会被禁止)。
真正体现“优先级”的场景是:如果某个类已经被父类加载器加载过了,子类加载器就不会再加载一遍,这就是类的共享与隔离机制。
打破双亲委派的情况
有些特殊场景需要绕过这种优先级机制,比如:
- Tomcat实现Web应用隔离,每个应用使用独立的类加载器,且部分情况下会先自己尝试加载,再委托父类,打破双亲委派。
- SPI(Service Provider Interface)机制中,Thread.currentThread().getContextClassLoader()用于加载第三方实现,因为启动类加载器无法加载应用级别的类。
基本上就这些。类加载的“优先级”本质是委托顺序和类加载器的层级控制,理解清楚双亲委派模型,就能掌握Java类加载的核心逻辑。










