什么是类加载的委派模型?

  • Post category:Java

类加载器的委派模型是Java中类加载器机制的核心,它通过双亲委派机制实现了类的加载、保证了JVM的安全性和稳定性。下面是详细讲解类加载器的委派模型的完整使用攻略。

一、什么是类加载的委派模型?

Java中的类加载是一个比较复杂的过程,而类加载器的委派模型就是用来协调和处理类加载的。Java类加载器采用了双亲委派模型,即当一个类加载器需要加载一个类时,它会先把这个任务委托给它的父类加载器,父类加载器再把任务委托给它的父类加载器,最终到达顶层的启动类加载器。如果所有父类加载器都无法找到这个类,子加载器才会自己尝试去加载这个类。这种委派模型保证了类的正确性、避免了重复加载和冲突,保障了JVM的安全性和稳定性。

二、类加载委派模型的效果

类加载器的委派模型有以下几个特点:

  1. 父类加载器优先

在类加载器需要加载一个类时,它首先把这个任务委托给它的父类加载器,父类加载器再把任务委托给它的父类加载器,最终到达顶层的启动类加载器。如果所有父类加载器都无法找到这个类,子加载器才会自己尝试去加载这个类。这样就可以保证在父类、子类、不同包名下的类不会产生冲突和混淆。

  1. 缓存机制

类加载器从文件或者网络中加载类时,会把它们缓存起来,以便后续加载时使用。如果一个类已经被加载,那么类加载器就不再继续加载,直接返回缓存中的类。这样就避免了重复加载和冲突。

  1. 安全保障

使用双亲委派模型可以保障JVM的安全性和稳定性。因为Java虚拟机在启动时使用的是启动类加载器,而启动类加载器只会加载Java的核心类库,而其他类库的加载是由Java程序员自己编写的类加载器实现的。这样,就可以保证控制在Java程序员手中,避免了恶意程序的插入。

三、类加载器委派模型示例

下面是两条使用示例:

示例1:验证类加载器委派模型

public class ClassLoaderTest {
    public static void main(String[] args) {
        ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
        while (classLoader != null) {
            System.out.println(classLoader.getClass().getName());
            classLoader = classLoader.getParent();
        }
        System.out.println(String.class.getClassLoader());
    }
}

这个示例中,我们创建了一个ClassLoaderTest类,并在main方法中获取了它的类加载器,并迭代输出它的每一个父类加载器,最后输出了String类的类加载器。运行结果如下:

sun.misc.Launcher$AppClassLoader
sun.misc.Launcher$ExtClassLoader
null
null

从结果可以看到,ClassLoaderTest的类加载器是AppClassLoader,它的父类加载器是ExtClassLoader。最后输出的String类的类加载器是null,说明String类是被Bootstrap ClassLoader加载的。这个例子验证了类加载器委派模型的有效性。

示例2:使用自定义类加载器加载类

public class CustomClassLoader extends ClassLoader {
    private String classPath;

    public CustomClassLoader(String classPath) {
        this.classPath = classPath;
    }

    @Override
    public Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] data = loadClassData(name);
        return defineClass(name, data, 0, data.length);
    }

    private byte[] loadClassData(String name) {
        String fileName = classPath + name.replace(".", "/") + ".class";
        try (InputStream is = new FileInputStream(new File(fileName));
             ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            byte[] buffer = new byte[1024];
            int len;
            while ((len = is.read(buffer)) != -1) {
                baos.write(buffer, 0, len);
            }
            return baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) throws Exception {
        CustomClassLoader classLoader = new CustomClassLoader("/Users/xxx/Desktop/");
        Class clazz  = classLoader.loadClass("TestClass");
        Object obj = clazz.newInstance();
        Method method = clazz.getDeclaredMethod("test", null);
        method.invoke(obj, null);
    }
}

这个示例中,我们创建了一个自定义的类加载器CustomClassLoader,通过TestClass类的全限定名把类的加载任务委派给父类加载器,如果父类加载器无法找到该类,则该自定义类加载器就会去自行加载该类。

loadClassData方法中,我们使用FileInputStream加载制定文件,并将文件的字节码数组返回。在findClass方法中,我们使用defineClass方法把类的字节码转换为Class对象。在main方法中,我们通过CustomClassLoader加载了TestClass类,并调用它的test方法打印输出。这个例子验证了双亲委派模型的安全保障和灵活性。

以上就是类加载器委派模型的完整使用攻略,希望对您有所帮助。