今天學習工廠模式解耦操作時凯肋,誤用了properties類的類加載器去獲取配置配置文件,報了空指針異常汽馋,查class類的源碼發(fā)現(xiàn)如下內(nèi)容:
/** Returns the class loader for the class. Some implementations may use
* null to represent the bootstrap class loader. This method will return
* null in such implementations if this class was loaded by the bootstrap class loader.
properties類的類加載器是bootstrap class loader,所以該方法返回的是null圈盔。
除了properties豹芯,我還用了object類和自定義的一些類來獲取類加載器,發(fā)現(xiàn)系統(tǒng)類使用時驱敲,都拋出了空指針異常铁蹈,而自定義的類在獲取加載器時可以正常操作
Object o = new Object();
ClassLoader classLoader1 = o.getClass().getClassLoader();
IAccountDao iAccountDao = new IAccountDaoImpl();
ClassLoader classLoader2 = iAccountDao.getClass().getClassLoader();
System.out.println(classLoader2);
System.out.println(classLoader1);
//運行結(jié)果是
//sun.misc.Launcher$AppClassLoader@135fbaa4
//null
通過getParent()方法可以看到分層情況:
IAccountDao iAccountDao = new IAccountDaoImpl();
ClassLoader classLoader2 = iAccountDao.getClass().getClassLoader();
System.out.println(classLoader2);
System.out.println(classLoader2.getParent());
System.out.println(classLoader2.getParent().getParent());
//結(jié)果是
//sun.misc.Launcher$AppClassLoader@135fbaa4
//sun.misc.Launcher$ExtClassLoader@2503dbd3
//null
查詢類加載器的種類時發(fā)現(xiàn),自定義的這些類是
類加載器按照層次众眨,從頂層到底層握牧,分為以下四種:
1.啟動類加載器:這個類加載器負責放在<JAVA_HOME>\lib目錄中的,或者被-Xbootclasspath參數(shù)所指定的路徑中的娩梨,并且是虛擬機識別的類庫加載到內(nèi)存中沿腰。啟動類加載器無法被Java程序直接引用。
2.擴展類加載器:這個類加載器由sun.misc.Launcher$ExtClassLoader
實現(xiàn)狈定。它負責<JAVA_HOME>\lib\ext目錄中的颂龙,或者被java.ext.dirs系統(tǒng)變量所指定的路徑中的所有類庫。用戶可以直接使用纽什。
3.應用程序類加載器:這個類由sun.misc.Launcher$AppClassLoader
實現(xiàn)措嵌。是ClassLoader中getSystemClassLoader()方法的返回值。它負責用戶路徑(ClassPath)所指定的類庫芦缰。用戶可以直接使用企巢。如果用戶沒有自己定義類加載器,默認使用這個让蕾。
4.自定義加載器:用戶自己定義的類加載器浪规。
雙親委派模型:
雙親委派模型要求除了頂層的啟動類加載器外,其他的類加載器都應當有自己的父類加載器涕俗。這里類加載器之間的父子關系一般不會以繼承關系來實現(xiàn)罗丰,而是都使用組合關系來復用父加載器的代碼
工作過程:
如果一個類加載器收到了類加載的請求,它首先不會自己去嘗試加載這個類再姑,而是把這個請求委派給父類加載器去完成萌抵,每一個層次的類加載器都是如此,因此所有的加載請求最終都應該傳遞到頂層的啟動類加載器中,只有當父類加載器反饋自己無法完成這個請求(它的搜索范圍中沒有找到所需的類)時绍填,子加載器才會嘗試自己去加載霎桅。
好處:
Java類隨著它的類加載器一起具備了一種帶有優(yōu)先級的層次關系。例如類Object讨永,它放在rt.jar中滔驶,無論哪一個類加載器要加載這個類,最終都是委派給啟動類加載器進行加載卿闹,因此Object類在程序的各種類加載器環(huán)境中都是同一個類揭糕,判斷兩個類是否相同是通過classloader.class這種方式進行的,所以哪怕是同一個class文件如果被兩個classloader加載锻霎,那么他們也是不同的類著角。
代碼測試時,其實還發(fā)現(xiàn)了另外一個問題旋恼,就是我初始化了兩個classLoader對象吏口,打印出來發(fā)現(xiàn)這兩個對象的類加載器竟然一模一樣,為什么呢冰更?
IAccountDao iAccountDao = new IAccountDaoImpl();
ClassLoader classLoader2 = iAccountDao.getClass().getClassLoader();
System.out.println(classLoader2);
System.out.println(classLoader2.getParent());
ClassLoader classLoader = BeanFactory.class.getClassLoader();
System.out.println(classLoader);
//執(zhí)行結(jié)果是
//sun.misc.Launcher$AppClassLoader@135fbaa4
//sun.misc.Launcher$ExtClassLoader@2503dbd3
//sun.misc.Launcher$AppClassLoader@135fbaa4
答案參考:
https://blog.csdn.net/weixin_42248137/article/details/80387305
參考:
https://www.cnblogs.com/Yanss/p/11711894.html
https://www.cnblogs.com/fengbs/p/7595849.html
https://blog.csdn.net/YingHuaNanHai/article/details/81264893