Java类加载器(ClassLoader)是Java虚拟机(JVM)中的一个重要组成部分,用于将Java类文件加载到JVM中,以便能够执行Java程序。在Java中,类加载器的设计采用了一种称为“双亲委派模式”(Parent Delegation Model)的机制,这种模式确保了Java类的加载能够遵循既定的规则,从而保证了类加载的安全性和一致性。
当我们谈论Java类加载器时,通常涉及到几个核心的概念:
1. Bootstrap ClassLoader(启动类加载器):这是最顶层的类加载器,由C++编写,是JVM自身的一部分。它负责加载存放在JAVA_HOME/lib目录或-Xbootclasspath参数指定路径下的类库。这个类加载器不是Java类,因此不能通过Java代码获取其引用。
2. Extension ClassLoader(扩展类加载器):这个类加载器负责加载JAVA_HOME/lib/ext目录或由java.ext.dirs系统变量指定位置中的类库。扩展类加载器是一个Java类,它在运行时被Bootstrap ClassLoader加载,并且它同样会加载扩展API中的类。
3. Application ClassLoader(应用程序类加载器):也被称为System ClassLoader(系统类加载器),它负责加载CLASSPATH环境变量所指定的路径、类路径(ClassPath)下的类库。一般情况下,它是Java应用程序中默认的类加载器。
双亲委派模式的工作原理是这样的:当一个类加载器接收到类加载请求时,它首先将请求委派给父类加载器,父类加载器再委派给自己的父类加载器,如此递归。这个递归过程会一直到达最顶层的Bootstrap ClassLoader。如果父类加载器无法完成加载任务,子类加载器才会尝试自己加载类。
这种模式的优点在于它可以有效防止类的重复加载,确保Java核心库的类型安全。比如,如果用户尝试使用Application ClassLoader加载rt.jar中的类,这个请求会被委派到Extension ClassLoader,最终到达Bootstrap ClassLoader,它会首先检查自己是否已经加载了这个类,如果已经加载,那么就不会再次加载。
同时,双亲委派模式也保证了Java核心类库的优先加载权。例如,当Extension ClassLoader尝试加载一个类时,如果这个类的名字是java.lang.Object,那么Bootstrap ClassLoader将无法加载这个类(因为Bootstrap ClassLoader负责加载的是lib目录下的核心Java类),但是Extension ClassLoader也不会尝试加载,因为它会默认Bootstrap ClassLoader已经加载了这个类。这就是为什么核心Java类总是由Bootstrap ClassLoader加载,从而确保了Java虚拟机核心库的一致性。
Java类加载器的这种机制也使得Java类加载器具有很好的扩展性,比如在Web服务器和应用服务器中经常使用自定义的类加载器来实现热部署、模块化等高级功能。开发者可以实现自己的类加载器来从特定来源(比如数据库、网络等)加载类。
需要注意的是,如果一个类已经被加载器加载到JVM中,那么这个类是无法被更新的。如果尝试使用同一个类加载器再次加载同一个类,将会抛出java.lang.LinkageError异常,异常信息为duplicate class definition。要更新一个类,只能创建一个新的类加载器实例来加载新类。对于已经被加载的类,开发者不需要进行任何操作,只要相关的类实例被垃圾回收器回收,JVM会在适当的时候卸载那些不再使用的类。
Java类加载器及其双亲委派模型是JVM实现安全、有效的类加载机制的关键,它们确保了Java类的加载能够有序进行,同时也为开发者提供了在需要时扩展或重写类加载行为的可能。