本章內容根據《深入理解Java虛擬機》第7章部分內容整理
?
? ? 1.什么是類加載器?
? ?在類加載階段,有一步是“通過類的全限定名來獲取描述此類的二進制字節流”,而所謂的類加載器就是實現這個功能的一個代碼模塊,這個動作是在Java虛擬機外部實現的,這樣做可以讓應用程序自己決定如何去獲取所需要的類。
? ?類加載器的作用:首先類加載器可以實現最本質的功能即類的加載動作。同時,它還能夠結合java類本身來確定該類在Java虛擬機中的唯一性。用通俗的話來說就是:比較兩個類是否相等,只有這兩個類是由同一個類加載器加載才有意義。否則,即使這兩個類是來源于同一個Class文件,只要加載它們的類加載器不同,那么這兩個類必定不相等。
? ? 2.雙親委派模型
? ?從虛擬機的角度來說,只存在兩種不同的類加載器:一種是啟動類加載器(Bootstrap ClassLoader),該類加載器使用C++語言實現,屬于虛擬機自身的一部分。另外一種就是所有其它的類加載器,這些類加載器是由Java語言實現,獨立于JVM外部,并且全部繼承自抽象類java.lang.ClassLoader。
? ?從Java開發人員的角度來看,大部分Java程序一般會使用到以下三種系統提供的類加載器:
? ?1)啟動類加載器(Bootstrap ClassLoader):負責加載JAVA_HOME\lib目錄中并且能被虛擬機識別的類庫到JVM內存中,如果名稱不符合的類庫即使放在lib目錄中也不會被加載。該類加載器無法被Java程序直接引用。
? ?2)擴展類加載器(Extension ClassLoader): 按《深入理解java虛擬機》這本書上所說,該加載器主要是負責加載JAVA_HOME\lib\ext目錄中的類庫,但是貌似在JDK的安裝目錄下,沒看到該指定的目錄 。該加載器可以被開發者直接使用。
? ?3)應用程序類加載器(Application ClassLoader):該類加載器也稱為系統類加載器,它負責加載用戶類路徑(Classpath)上所指定的類庫,開發者可以直接使用該類加載器,如果應用程序中沒有自定義過自己的類加載器,一般情況下這個就是程序中默認的類加載器。
? ?我們的應用程序都是由這三類加載器互相配合進行加載的,我們也可以加入自己定義的類加載器。這些類加載器之間的關系如下圖所示:
? ?如上圖所示的類加載器之間的這種層次關系,就稱為類加載器的雙親委派模型(Parent Delegation Model)。該模型要求除了頂層的啟動類加載器外,其余的類加載器都應當有自己的父類加載器。子類加載器和父類加載器不是以繼承(Inheritance)的關系來實現,而是通過組合(Composition)關系來復用父加載器的代碼。
? ?雙親委派模型的工作過程為: 如果一個類加載器收到了類加載的請求,它首先不會自己去嘗試加載這個類,而是把這個請求委派給父類加載器去完成,每一個層次的加載器都是如此,因此所有的類加載請求都會傳給頂層的啟動類加載器,只有當父加載器反饋自己無法完成該加載請求(該加載器的搜索范圍中沒有找到對應的類)時,子加載器才會嘗試自己去加載 。
? ?使用這種模型來組織類加載器之間的關系的好處是Java類隨著它的類加載器一起具備了一種帶有優先級的層次關系。例如java.lang.Object類,無論哪個類加載器去加載該類,最終都是由啟動類加載器進行加載,因此Object類在程序的各種類加載器環境中都是同一個類。否則的話,如果不使用該模型的話,如果用戶自定義一個java.lang.Object類且存放在classpath中,那么系統中將會出現多個Object類,應用程序也會變得很混亂。如果我們自定義一個rt.jar中已有類的同名Java類,會發現JVM可以正常編譯,但該類永遠無法被加載運行。
? ?在rt.jar包中的java.lang.ClassLoader類中,我們可以查看類加載實現過程的代碼,具體源碼如下:
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException{ // First, check if the class has already been loaded Class c = findLoadedClass(name); if (c == null) { try { if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { // If still not found, then invoke findClass in order // to find the class. c = findClass(name); } } if (resolve) { resolveClass(c); } return c; }
?
? ?通過上面代碼可以看出,雙親委派模型是通過loadClass()方法來實現的,根據代碼以及代碼中的注釋可以很清楚地了解整個過程其實非常簡單:先檢查是否已經被加載過,如果沒有則調用父加載器的loadClass()方法,如果父加載器為空則默認使用啟動類加載器作為父加載器。如果父類加載器加載失敗,則先拋出ClassNotFoundException,然后再調用自己的findClass()方法進行加載。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
