上篇文章說了java類的加載,驗證、準備、解析、初始化。類的初始化必須是類加載完才執行,是以類的構造方法初始化是在靜态方法之後執行。
一、類加載和雙親委派機制
前面類加載主要通過類加載器實作,類加載器有這幾種:
1、引導類加載器:負責加載支撐JVM運作的位于JRE的lib目錄下核心類庫,比如chaset.jar和rt.jar等。(c++實作)
2、擴充類加載器:負責加載支撐JVM運作的位于jre的lib目錄下的ext擴充目錄中的jar類包。
3、應用程式加載器:負責加載classPath路徑下的類包,主要加載自己寫的類。
4、自定義加載器:負責加載使用者自定義路徑下的類包。
由上面代碼執行的結果可以看到:
為什麼第一個列印的是null呢,因為引導類加載器是c++實作的,java不會顯示。
同理parentBootStrap就是加載器就是基類加載器,也是null。它的子類是ext加載器,ext的子類是app加載器,可以通過getSystemClassLoader來擷取到。
為什麼appClassLoader明明是最子類,而它會列印所有的包呢?
這就是雙親委派設定導緻如此的,因為每次加載會從他的父加載器去加載,當bootStrap從核心類庫加載不到,才會依次讓子加載器嘗試加載。
Launcher類最核心的代碼是這兩塊
getExtClassLoader() 和 getAppClassLoader()
ExtClassLoader是構造擴充類加載器,構造過程中将其父加載器設定為null。
getAppClassLoader構造應用類加載器,構造過程中将父加載器設定為ExtClassLoader。
需要設定一下,equals我們自己的類,就可以隻看我們自己的斷點。
當我們運作昨天寫的代碼,斷點就會走到loadClass這裡,點進去他的super。
這裡的findLoaderClass代表如果找到就直接傳回。
這裡第一次進來肯定是null,是以判斷他的parent。
我們這裡的this指的是appClassLoader,
是以他的父加載器我們之前看了是ExtClassLoader。
這時候遞歸調用這個loadClass,這時候則是ExtClassLoader調用。
這時候ExtClassLoader的父加載器是null,這時候走下面findBootstrap引導類加載器。
這時bootStrap類加載器肯定傳回null。
于是開始進入findClass。
這裡的findClass則是會調用URLClassLoader裡的findClass方法。
這裡會嘗試加載又會回到appClassLoader。