1. 程式人生 > >不同的類載入器載入的類不是同一個類

不同的類載入器載入的類不是同一個類

一,有兩個術語,一個叫“定義類載入器”,一個叫“初始類載入器”。
比如有如下的類載入器結構:
bootstrap
  ExtClassloader
    AppClassloader
    -自定義clsloadr1
    -自定義clsloadr2 
如果用“自定義clsloadr1”載入java.lang.String類,那麼根據雙親委派最終bootstrap會載入此類,那麼bootstrap類就叫做該類的“定義類載入器”,而包括bootstrap的所有得到該類class例項的類載入器都叫做“初始類載入器”。

二,所說的“名稱空間”,是指jvm為每個類載入器維護的一個“表”,這個表記錄了所有以此類載入器為“初始類載入器”(而不是定義類載入器,所以一個類可以存在於很多的名稱空間中)載入的類的列表,所以,題目中的問題就可以解釋了:


CLTest是AppClassloader載入的,String是通過載入CLTest的類載入器也就是AppClassloader進行載入,但最終委派到bootstrap載入的(當然,String類其實早已經被載入過了,這裡只是舉個例子)。所以,對於String類來說,bootstrap是“定義類載入器”,AppClassloader是“初始類載入器”。根據剛才所說,String類在AppClassloader的名稱空間中(同時也在bootstrap,ExtClassloader的名稱空間中,因為bootstrap,ExtClassloader也是String的初始類載入器),所以CLTest可以隨便訪問String類。這樣就可以解釋“處在不同名稱空間的類,不能直接互相訪問”這句話了。


三,一個類,由不同的類載入器例項載入的話,會在方法區產生兩個不同的類,彼此不可見,並且在堆中生成不同Class例項。

四,那麼由不同類載入器例項(比如-自定義clsloadr1,-自定義clsloadr2)所載入的classpath下和ext下的類,也就是由我們自定義的類載入器委派給AppClassloader和ExtClassloader載入的類,在記憶體中是同一個類嗎?
所有繼承ClassLoader並且沒有重寫getSystemClassLoader方法的類載入器,通過getSystemClassLoader方法得到的AppClassloader都是同一個AppClassloader例項,類似單例模式。

在ClassLoader類中getSystemClassLoader方法呼叫私有的initSystemClassLoader方法獲得AppClassloader例項,在initSystemClassLoader中:
sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
。。。
scl = l.getClassLoader();
AppClassloader是sun.misc.Launcher類的內部類,Launcher類在new自己的時候生成AppClassloader例項並且放在自己的私有變數loader裡:
loader = AppClassLoader.getAppClassLoader(extclassloader);
值得一提的是sun.misc.Launcher類使用了一種類似單例模式的方法,即既提供了單例模式的介面getLauncher()又把建構函式設成了public的。但是在ClassLoader中是通過單件模式取得的Launcher 例項的,所以我們寫的每個類載入器得到的AppClassloader都是同一個AppClassloader類例項。
這樣的話得到一個結論,就是所有通過正常雙親委派模式的類載入器載入的classpath下的和ext下的所有類在方法區都是同一個類,堆中的Class例項也是同一個。