類加載器
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()方法來打破這個模型