类加载器的委派模型是Java中类加载器机制的核心,它通过双亲委派机制实现了类的加载、保证了JVM的安全性和稳定性。下面是详细讲解类加载器的委派模型的完整使用攻略。
一、什么是类加载的委派模型?
Java中的类加载是一个比较复杂的过程,而类加载器的委派模型就是用来协调和处理类加载的。Java类加载器采用了双亲委派模型,即当一个类加载器需要加载一个类时,它会先把这个任务委托给它的父类加载器,父类加载器再把任务委托给它的父类加载器,最终到达顶层的启动类加载器。如果所有父类加载器都无法找到这个类,子加载器才会自己尝试去加载这个类。这种委派模型保证了类的正确性、避免了重复加载和冲突,保障了JVM的安全性和稳定性。
二、类加载委派模型的效果
类加载器的委派模型有以下几个特点:
- 父类加载器优先
在类加载器需要加载一个类时,它首先把这个任务委托给它的父类加载器,父类加载器再把任务委托给它的父类加载器,最终到达顶层的启动类加载器。如果所有父类加载器都无法找到这个类,子加载器才会自己尝试去加载这个类。这样就可以保证在父类、子类、不同包名下的类不会产生冲突和混淆。
- 缓存机制
类加载器从文件或者网络中加载类时,会把它们缓存起来,以便后续加载时使用。如果一个类已经被加载,那么类加载器就不再继续加载,直接返回缓存中的类。这样就避免了重复加载和冲突。
- 安全保障
使用双亲委派模型可以保障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
方法打印输出。这个例子验证了双亲委派模型的安全保障和灵活性。
以上就是类加载器委派模型的完整使用攻略,希望对您有所帮助。