类加载器、双亲委派模型
目錄
1.簡介
2.類和類加載器
3.雙親委派模型
3.1 啟動類加載器:
3.2 擴展類加載器
3.3應(yīng)用程序類加載器
3.4? 類加載器的雙親委派模型(Parents Delegation Model)
雙親委派模型的工作過程:
好處:
實現(xiàn):
4.破壞雙親委派模型
1.簡介
虛擬機設(shè)計團隊把類加載階段的“通過一個類的全限定名來獲取描述此類的二進制字節(jié)流”這個動作。實現(xiàn)這個動作的代碼模塊稱為“類加載器”。
?
它是在JVM外部實現(xiàn)的,以便讓應(yīng)用程序自己決定如何獲取所需要的類。
2.類和類加載器
對于任何一個類,都需要由加載它的類加載器和這個類本身一同確立其在JVM中的唯一性。
每一個類加載器,都有一個獨立的類名稱空間。即,比較兩個類是否“相等”,只有在這兩個類是由同一個類加載器加載的前提下才有意義,否則,即使兩個類來源于同一個Class文件,被同一個虛擬機加載,只要加載它們的類加載器不同,那么這兩個類就必定不相等。
- “相等”:包括代表類對象的equals()方法、isAssignableFromo()方法、isInstance()方法的返回結(jié)果,也包括使用instanceof關(guān)鍵字做對象所屬關(guān)系判定等情況。
- 如果沒有注意到類加載器的影響,在某些情況下,可能會產(chǎn)生具有迷惑性的結(jié)果,如下代碼:
輸出:
上述代碼構(gòu)造了一個簡單的類加載器。
- 可加載與自己同一路徑下的Class文件。
- 使用這個類加載器加載了一個名為“CSDNpattern.Test”的類,并實例化了這個類的對象。
- 輸出結(jié)果中,第一句表明這個類確實是“CSDNpattern.Test”;但第二句發(fā)現(xiàn)這個類和“CSDNpattern.Test”做所屬類型檢查的時候卻返回了false。
- 因為虛擬機中存在了兩個Test類,一個室友系統(tǒng)應(yīng)用程序類加載器加載的,一個是由自定義的類加載器加載的。
- 雖然都是來自同一個Class文件,但是是兩個獨立的類,做對象所屬類型檢查時結(jié)果自然為false。
3.雙親委派模型
從JVM角度來看,只存在兩種不同的類加載器:
- 啟動類加載器(BootStrap ClasLoader):使用C++實現(xiàn),是虛擬機自身的一部分;
- 所有其他的類加載器:由Java實現(xiàn),獨立于虛擬機外部,并且全都繼承自抽象類java.lang.Object。
從Java開發(fā)人員角度,還可以分的更細(xì),絕大部分Java程序都會用到一下3種系統(tǒng)提供的類加載器:
3.1 啟動類加載器:
- 負(fù)責(zé)將存放在<JAVA_HOME>\lib目錄里的,或者被-Xbootclasspath參數(shù)指定的路徑中的,并且是虛擬機識別的(僅按照文件名識別,如rt.jar,名字不符合的類庫即使放在lib目錄中也不會被加載)類庫加載到虛擬機內(nèi)存中。
- 它無法被Java程序直接引用。
- 用戶在編寫自定義類加載器時,如果需要把加載請求為派給引導(dǎo)類加載器,納智捷使用null代替即可。如下代碼所示(提示錯):
3.2 擴展類加載器
Extension ClassLoader
負(fù)責(zé)加載<JAVA_HOME>\lib\ext目錄中的,或者被java.ext.dirs系統(tǒng)變量所指定的路徑中的所有類庫,開發(fā)者可以使用擴展類加載器。
3.3應(yīng)用程序類加載器
Application ClassLoader
它是ClassLoader中的getSystemClassLoader()放的返回值,所有一般也稱為系統(tǒng)類加載器。
它負(fù)責(zé)加載用戶類路徑(ClassPath)上所指定的類庫,開發(fā)者可以直接使用這個類加載器。
如果應(yīng)用程序中沒有自定義過自己的類加載器,一般情況系下這個就是程序中的默認(rèn)的類加載器。
?
我們的應(yīng)用陳香菇都是由這3種類加載器相互配合進行加載的。
如有必要,還可以加入自定義的類加載器。
3.4? 類加載器的雙親委派模型(Parents Delegation Model)
這些類加載器的關(guān)系一般如下圖所示:
圖示的這種類加載器之間的這種層次關(guān)系,稱為類加載器的雙親委派模型(Parents Delegation Model)
雙親委派模型中要求除了頂層的啟動類加載器外,其余的類加載器都應(yīng)當(dāng)有自己的父類加載器。
這里的類加載器之間的父子關(guān)系一般不會以繼承(inheritance)的關(guān)系來實現(xiàn),而是使用組合(Composition)關(guān)系來復(fù)用父加載器的代碼。
類加載器的雙親委派模型在JDK1.2期間被引入并被廣泛應(yīng)用于之后幾乎所有的Java程序中。
但它并不是一個強制性的約束模型,而是Java設(shè)計者推薦給開發(fā)者的一種類加載器實現(xiàn)方式。
3.4.1 雙親委派模型的工作過程
3.4.2 好處
Java類隨著它的類加載器一起舉杯了一種帶有優(yōu)先級的層次關(guān)系。
例如,類java.lang.Object,它存放在rt.jar中,無論哪一個類加載器都要加載這個類,最終都是為派給處于模型最頂端的啟動類加載器進行加載。因此Object類在程序的各個類加載器環(huán)境中都是同一個類。
相反,如果沒有使用這個模型,由各個類加載器自行去加載的話,如果用戶自己編寫了一個稱為java.lang.Object的類,并放在程序ClassPath中,那系統(tǒng)將會出現(xiàn)多個不同的Object類。Java類型體系中最基礎(chǔ)的行為也就無法保證,應(yīng)用程序也變得一片混亂。
3.4.3 實現(xiàn)
實現(xiàn)這個模型的代碼都集中在在java.lang.ClassLoader的loadClass()中。如下代碼所示:
{//首先檢查請求的類是否已經(jīng)被加載過了Class c=findLoadedClass(name);if(c==null) {try {if(parent!=null)c=parent.loadClass(name,false);elsec=findBootStrapClassOrNull(name);}catch(ClassNotFoundException e) {//如果父類加載器 拋出ClassNotFoundException//說明父類加載器無法完成加載請求}if(c==null) {//在父類加載器無法完成加載的時候//再調(diào)用本身的findClass方法來進行類加載c=findClass(name);}}if(resolve) {resolveClass(c);} }邏輯:
4.破壞雙親委派模型
雙親委派模型主要出現(xiàn)過3次較大規(guī)模的“被破壞”情況;
整理自《深入理解Java虛擬機——JVM高級特性與最佳實踐》
總結(jié)
以上是生活随笔為你收集整理的类加载器、双亲委派模型的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JVM运行时结构、Java内存管理、JV
- 下一篇: Hashtable源码分析