类加载器
JVM提供了三种类加载器:启动类加载器、扩展类加载器、应用程序类加载器。他们所加载的内容如下:
- 启动类加载器:加载JAVA_HOME/lib下面的jar;
- 扩展类加载器:加载JAVA_HOME/lib/ext下面的jar;
- 应用程序类加载器:加载用户路径下的jar,比如我们自己写的代码,会加载classpath路径下的类;
除了上述三种方式,我们可以继承ClassLoad类来自定义自己的类加载器。
双亲委派模型
双亲委派模型:当一个类加载器收到类加载请求的时候,不会自己去加载这个类,而是向上请求自己的父加载器去加载这个类,父加载器也会继续向上请求它的父加载器去加载这个类,直到根类加载器,即启动类加载器,如果启动类加载器中找不到这个类,则依次向下请求其子类加载器去加载这个类,即扩展类加载器加载这个类,如果扩展类加载器也没有这个类,则继续向下请求,如果应用程序类加载器还没有找到这个类,则交给自定义加载器来完成,如果最后自定义加载器也没有,则抛出ClassNotFound异常。
双亲委派模型的好处是能保证加载类的唯一性和安全性,比如你重写了一个String类,那么由于JVM已经存在了String类,所以最后加载的时候由于会不断地向上请求父类加载器,而父加载器是已经存在String类的,所以你定义的String类便不会加载。
源码如下:
protected synchronized Class<?> loadClass(String name,boolean resolve)throws ClassNotFoundException{
//check the class has been loaded or not
Class c = findLoadedClass(name);
if(c == null){
try{
// 如果父类加载器不是null
if(parent != null){
// 由父类加载器加载
c = parent.loadClass(name,false);
}else{
// 否则由启动类加载器加载
c = findBootstrapClassOrNull(name);
}
}catch(ClassNotFoundException e){
//if throws the exception ,the father can not complete the load
}
// 如果启动类加载器还没有,则由自己加载
if(c == null){
c = findClass(name);
}
}
if(resolve){
resolveClass(c);
}
return c;
}
如何打破双亲委派模型
可以继承java.lang.ClassLoader类并重写loadClass()方法来打破这个模型