JVM中的类加载器
JVM中的类加载器可以分为以下三个层次:
1. 启动类加载器(Bootstrap ClassLoader):负责加载Java的核心类库,如rt.jar、resources.jar等。
2. 扩展类加载器(Extension ClassLoader):负责加载JRE扩展目录(ext)中的jar包。
3. 应用程序类加载器(Application ClassLoader):负责加载应用程序classpath目录下的类,也就是我们自己编写的Java类。
下面分别以这三种类加载器为例,说明它们的核心功能以及如何使用它们加载类。
1. 启动类加载器(Bootstrap ClassLoader)
启动类加载器是JVM内置的类加载器,它负责加载Java的核心类库,如rt.jar、resources.jar等。由于启动类加载器是C++语言实现的,并不是Java代码,因此我们无法直接操作它。
2. 扩展类加载器(Extension ClassLoader)
扩展类加载器是Java语言实现的类加载器,它负责加载JRE扩展目录(ext)中的jar包。在Windows上,JRE扩展目录通常是`C:\Program Files\Java\jdk\jre\lib\ext`。如果我们需要在程序中加载某个JRE扩展中的类,可以通过如下代码实现:
URL url = new URL("file:/C:/Program Files/Java/jdk/jre/lib/ext/my_extension.jar");
URLClassLoader extClassLoader = new URLClassLoader(new URL[] {url}, null);
Class<?> clazz = extClassLoader.loadClass("com.example.MyExtensionClass");
Object obj = clazz.newInstance();
在上述代码中,我们首先创建了一个`URLClassLoader`对象,它将扩展目录下的jar包添加到了classpath中。然后,我们调用该类加载器的`loadClass()`方法来加载指定名称的类。
3. 应用程序类加载器(Application ClassLoader)
应用程序类加载器是Java语言实现的类加载器,它负责加载应用程序classpath目录下的类,也就是我们自己编写的Java类。如果我们需要在程序中加载某个Java类,可以通过如下代码实现:
MyClassLoader myClassLoader = new MyClassLoader();
Class<?> clazz = myClassLoader.loadClass("com.example.MyClass");
Object obj = clazz.newInstance();
在上述代码中,我们自定义了一个类加载器`MyClassLoader`,继承自`java.lang.ClassLoader`类,并重写了`findClass()`方法。然后,我们创建了一个`MyClassLoader`对象,并调用其`loadClass()`方法来加载指定名称的类。最后,我们通过反射机制创建了该类的实例,并调用它的方法完成业务逻辑。
需要注意的是,在实际开发中,我们需要注意类加载器的双亲委派模型,确保类加载器之间的协作和依赖关系。
此外,还有一些其他的类加载器,比如Tomcat的Web应用程序类加载(WebAppClassLoader),它负责加载Web应用程序中的类。
类加载器的核心功能
类加载器的核心功能是将字节码文件加载到内存中,并创建对应的Class对象。具体来说,类加载器会执行以下步骤:
1. 加载(Load):查找并加载字节码文件。
2. 验证(Verify):验证字节码文件的正确性和安全性。
3. 准备(Prepare):为类变量(静态变量)分配内存,并设置默认初始值。
4. 解析(Resolve):将符号引用转换为直接引用。
5. 初始化(Initialize):执行类构造器<clinit>()方法,初始化类变量和静态代码块。
在JVM运行时,每个类都被对应一个ClassLoader对象所加载,ClassLoader对象之间组成了一个父子层次结构。当需要加载某个类时,JVM会先委托父类加载器去加载,如果父类加载器无法加载,则由子类加载器去加载。这样就形成了一个类加载器的委托模型,也称为类加载器的双亲委派模型。该模型保证了Java类的唯一性和安全性,避免了类的重复加载和冲突。