简介
Java语言采用的是基于类的面向对象编程思想,当Java程序需要使用一个类时,它会根据类的名称来寻找对应的字节码文件,并将字节码文件加载到JVM中。类加载的委派模型是指,当Java程序需要加载一个类时,先委派父类加载器去加载该类,如果父类加载器无法加载该类,则交给当前类加载器自行加载。
工作原理
类加载的委派模型是Java虚拟机(JVM)用来保证Java核心api不被篡改的重要机制之一。在JVM创建时,会设置一个系统类加载器,所有其他的类加载器都是由系统类加载器创建的。类加载器按照父子关系形成了一个树形结构,每个类加载器实例都有一个指向其父类加载器实例的引用。
在实际加载一个类时,JVM会依次将该任务委派给当前线程的父类加载器实例去完成。如果父类加载器可以成功加载该类,加载过程结束。如果父类加载器无法完成加载任务,则将任务转交给他的父类加载器,直到顶层的启动类加载器为止。如果启动类加载器依然找不到要加载的类,则会抛出ClassNotFoundException异常。
这个过程中,一个类被加载时,本质上只是其对应的.class文件被读取到了JVM中,并在JVM的内存区域中生成一个代表该类的Class对象,这个Class对象对于JVM来说是唯一的,即同一个类被加载多次,JVM都只会为其生成一个Class对象。
示例
示例1:
示例代码:
public class MyClassLoader {
public static void main(String[] args) {
//获取系统类加载器
ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();
System.out.println("系统类加载器:" + appClassLoader);
//获取系统类加载器的父类加载器——扩展加载器
ClassLoader extensionClassLoader = appClassLoader.getParent();
System.out.println("扩展类加载器:" + extensionClassLoader);
//获取扩展类加载器的父类加载器——启动类加载器
ClassLoader bootstrapClassLoader = extensionClassLoader.getParent();
System.out.println("启动类加载器:" + bootstrapClassLoader);
}
}
该示例代码输出:
系统类加载器:jdk.internal.loader.ClassLoaders$AppClassLoader@2b193f2d
扩展类加载器:jdk.internal.loader.ClassLoaders$PlatformClassLoader@1f96302d
启动类加载器:null
示例2:
示例代码:
public class ClassLoaderDemo {
public static void main(String[] args) throws Exception {
// 获取一个系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
// 通过系统类加载器加载一个类
Class<?> clazz = systemClassLoader.loadClass("java.lang.String");
// 打印该类的类加载器——因为是由系统类加载器加载的,所以输出是AppClassLoader
System.out.println("类加载器:" + clazz.getClassLoader());
}
}
该示例代码输出:
类加载器:jdk.internal.loader.ClassLoaders$AppClassLoader@2b193f2d
总结
类加载器的委派模型是Java虚拟机保证api被加载时不被篡改的重要机制之一。在使用ClassLoader类加载器加载类时,其实是按照委派模型去执行,在每次委派给父ClassLoader加载类时,都会先到其父ClassLoader中查找是否已经加载。这种机制避免了类名相同但来源不同的类出现混乱,从而保证了Java程序的安全性。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:什么是类加载的委派模型? - Python技术站