类加载器是Java虚拟机向内存中加载类文件的组件之一,类加载器的双亲委派模型是指在类加载的过程中,先让父类加载器尝试加载类,如果父类加载器无法加载,则让子类加载器尝试加载。这种模型可以保证类的加载安全性、防止类的重复加载,并且可以避免程序中的类冲突问题。
双亲委派机制的具体实现原理如下:
1.当一个类需要被加载时,首先由它的父类加载器去查找是否已经加载了该类,如果已经加载,则直接返回该类;否则,该类交由它的父类加载器的父类加载器去查找,直至最顶层的类加载器(Bootstrap ClassLoader)。
2.当最顶层的类加载器无法加载该类时,依次向下委派给它的子类加载器加载,如果子类加载器都失败了,则抛出 ClassNotFoundException 异常。
下面以两个示例来说明双亲委派模型的实现原理:
1.自定义ClassLoader并使用
public class MyClassLoader extends ClassLoader {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
//查找已经加载的类,如果存在则直接返回该类
Class<?> clazz = findLoadedClass(name);
if (clazz != null) {
return clazz;
}
//如果没有找到已经加载的类,则交由父类去查找
if (getParent() != null) {
return getParent().loadClass(name);
}
//最顶层的类加载器也找不到,则使用自定义的方式进行加载
return defineClass(name, classBytes, 0, classBytes.length);
}
}
在自定义的 ClassLoader 中,如果需要加载某个类,则首先查找系统中是否已经加载过该类,如果已经加载则直接返回该类,否则再交由父类加载器查找。
2.自定义类加载器并破坏双亲委派模型
public class MyClassLoader extends ClassLoader {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
//如果要加载的类是java.lang.String,则使用自定义的方式进行加载
if ("java.lang.String".equals(name)) {
return defineClass(name, classBytes, 0, classBytes.length);
}
//否则交由父类加载器查找
if (getParent() != null) {
return getParent().loadClass(name);
}
throw new ClassNotFoundException(name);
}
}
在这个示例中,当要加载的类是 java.lang.String 时,自定义的类加载器会直接加载该类,破坏了双亲委派机制。因此,在使用自定义类加载器时需要严格遵循双亲委派机制,避免出现类加载的异常和冲突问题。