JavaSE--类加载器
參考:http://www.importnew.com/6581.html
Java 編譯器會為虛擬機轉換源指令。虛擬機代碼存儲在以 .class 為擴展名的類文件中,每個類文件都包含某個類或者接口的定義和代碼實現。這些類文件必須由一個程序進行解釋,該程序能夠將虛擬機的指令集翻譯成目標機器的機器語言。
虛擬機值加載程序執行時所需要的類文件。
?
類加載機制并非只使用單個的類加載器。每個 Java 程序至少擁有三個類加載器:
引導類加載器
擴展類加載器
系統類加載器(有時也稱為應用類加載器)
引導類加載器負責加載系統類(通常從 JAR 文件 rt.jar 中進行加載)。它是虛擬機不可分割的一部分,而且通常是用 C 語言來實現的。引導類加載器沒有對應的 ClassLoader 對象。
擴展類加載器用于從 jre/lib/ext 目錄加載 “標準的擴展”。可以將 JAR 文件放入該目錄,這樣即使沒有任何類路徑,擴展類加載器也可以找到其中的各個類。
系統類加載器用于加載應用類。它在由 CLASSPATH 環境變量或者 -classpath 命令行選項設置的類路徑中的目錄里或者是 JAR/ZIP 文件里查找這些類。
在 Oracle 的 Java 語言實現中,擴展類加載器和系統類加載器都是用 Java 來實現的。它們都是 URLClassLoader 類的實例。
警告:如果將 JAR 文件放入 jre/lib/ext 目錄中,并且在它的類中有一個類需要調用系統類或者擴展類,那么就會遇到麻煩。擴展類加載器并不使用類路徑。
除了所有已經提到的位置,還可以從 jre/lib/endorsed 目錄中加載類。這種機制只能用于將某個標準的 Java 類庫替換為更新的版本(例如那些支持 XML 和 CORBA 的類)。
?
類加載器有一種父/子關系。除了引導類加載器外,每個類加載器都有一個父類加載器。根據規定,類加載器會為它的父類加載器提供一個機會,以便加載任何給定的類,并且只有在其父類加載器加載失敗時,它才會加載該給定類。
某些程序具有插件架構,其中代碼的某些部分是作為可選的插件打包的。如果插件被打包為 JAR 文件,那就可以直接用 URLClassLoader 類的實例去加載這些類。
1 package classloader; 2 3 import java.net.MalformedURLException; 4 import java.net.URL; 5 import java.net.URLClassLoader; 6 7 public class URLDemo { 8 9 public static void main(String[] args) throws MalformedURLException, ClassNotFoundException, InstantiationException, IllegalAccessException { 10 URL url= new URL("file:\\E:\\project_neon1\\Demo2\\commons-codec-1.9.jar"); 11 URLClassLoader pluginLoader = new URLClassLoader(new URL[] {url}); 12 Class<?> c1 = pluginLoader.loadClass("org.apache.commons.codec.binary.Base64"); 13 } 14 15 }因為在 URLClassLoader 構造器中沒有指定父類加載器,因此 pluginLoader 的父親就是系統類加載器。
大多數時候,你不必操心類加載的層次結構。通常,類是由于其他的類需要它而被加載的,而這個過程對你是透明的。
偶爾,你也會需要干涉和指定類加載器。
考慮下面的例子:
你的應用的代碼包含一個助手方法,它要調用 Class.forName(classNameString)。
這個方法是從一個插件類中被調用的。
而 classNameString 指定的正是一個包含在這個插件的 JAR 中類。
插件的作者很合理地期望這個類應該被加載。但是,助手方法的類是由系統類加載器加載的,這正式 Class.forName 所使用的類加載器。而對于它來說,在插件 JAR 中的類是不可視的,這種現象被稱為類加載器倒置。
要解決這個問題,助手方法需要使用恰當的類加載器,它可以要求類加載器作為其一個參數傳遞給他。或者,它可以要求將恰當的類加載器設置成為當前線程的上下文類加載器。
每個線程都有一個對類加載器的引用,稱為上下文類加載器。主線程的上下文類加載器是系統類加載器。當新線程創建時,它的上下文類加載器會被設置成為創建該線程的上下文類加載器。因此,如果你不做任何特殊的操作,那么所有線程就都將它們的上下文類加載器設置為系統類加載器。
可以通過下面的調用將上下文類加載器設置成為任何類加載器。
1 Thread t = Thread.currentThread(); 2 t.setContextClassLoader(loader);然后助手方法可以獲取這個上下文類加載器:
1 Thread t = Thread.currentThread(); 2 ClassLoader loader = t.getContextClassLoader(); 3 Class cl = loaser.loadClass(className);當上下文類加載器設置為插件類加載器時,問題依舊存在。應用設計者必須作出決策:通常,當調用由不同的類加載器加載的插件類的方法時,進行上下文類加載器的設置是一種好的思路;或者,讓助手方法的調用者設置上下文類加載器。
如果你編寫了一個按名字來加載類的方法,那么讓調用者在傳遞顯示的類加載器和使用上下文類加載器之間進行選擇就是一種好的做法。不要直接使用該方法所屬的類的類加載器。
?
在同一個虛擬機中,可以有兩個類,它們的類名和包名都是相同的。類是由它的全名和類的加載器來確定的。這項技術在加載來自多處的代碼時很有用。例如 servlets 和 EJB 的 “熱部署”。
?
?
?
我們可以編寫自己的用于特殊目的的類加載器,這使得我們可以在向虛擬機傳遞字節碼之前執行定制的檢查。
如果要編寫自己的類加載器,只需要繼承 ClassLoader 類,然后覆蓋下面這個方法
findClass(String className)ClassLoader 超類的 loadClass 方法用于將類的加載操作委托給其父類加載器去進行,只有當該類尚未加載并且父類加載器也無法加載該類時,才調用 findClass 方法。
如果要實現該方法,必須做到以下幾點:
1) 為來自本地文件系統或者其他來源的類加載其字節碼
2) 調用 ClassLoader 超類的 defineClass 方法,向虛擬機提供字節碼
?
轉載于:https://www.cnblogs.com/microcat/p/7150758.html
總結
以上是生活随笔為你收集整理的JavaSE--类加载器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 保姆级教程,手把手教你制作数据分析报告
- 下一篇: Java怎么安装 详细教程来了 附带安装