您好,登錄后才能下訂單哦!
本篇內容介紹了“java類加載過程分為哪些步驟”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
它是Java將字節碼數據從不同的數據源讀取到JVM中,并映射為JVM認可的數據結構(Class對象)。這里的數據源可能是各種各樣的形態,如jar文件、class文件,甚至是網絡數據源等。如果輸入數據不是ClassFile的結構,則會拋出ClassFormatError。
加載階段是用戶參與的階段,我們可以自定義類加載器,去實現自己的類加載過程。
這是核心的步驟,簡單說是把原始的類定義信息平滑地轉化入JVM運行的過程中。這里可進一步細分為三個步驟:
驗證(Verification),這是虛擬機安全的重要保障,JVM需要核檢字節信息是符合Java虛擬機規范的,否則就被認為是VerifyError。這樣就防止了惡意信息或者不合規的信息危害JVM的運行。驗證階段有可能觸發更多class的加載。
準備(Preparation),創建類或接口中的靜態變量,并初始化靜態變量的初始值。但這里的“初始化”和下面的顯式初始化階段是有區別的,側重點在于分配所需要的內存空間,不會去執行更進一步的JVM指令。
解析(Resolution),在這一步會將常量池中的符號引用(symbolic reference)替換為直接引用。在Java虛擬機規范中,詳細介紹了類、接口、方法和字段等各個方面的解析。
這一步真正去執行類初始化的代碼邏輯,包括靜態字段復制的動作,以及執行類定義中的靜態初始化塊內的邏輯。編譯器在編譯階段就會把這部分邏輯整理好,父類型的初始化邏輯優先于當前類型的邏輯。
啟動類加載器(Bootstrap Class-Loader),加載jre/lib下面的jar文件,如rt.jar。它是個超級公民,即使是在開啟了Security Manager的時候,JDK仍賦予了它加載的程序AllPermission。
對于做底層開發的工程師,有的時候可能不得不去試圖修改JDK的基礎代碼,也就是通常意義上的核心類庫,我們可以使用下面的命令行參數。
# 指定新的 bootclasspath,替換 java.* 包的內部實現
java -Xbootclasspath:<your_boot_classpath> your_App
# a 意味著 append,將指定目錄添加到 bootclasspath 后面
java -Xbootclasspath/a:<your_dir> your_App
# p 意味著 prepend,將指定目錄添加到 bootclasspath 前面
java -Xbootclasspath/p:<your_dir> your_App
用法其實很易懂,例如,使用最常見的“/p”,既然是前置,就有機會替換個別基礎類的實現。
我們一般可以使用下面方法獲取父加載器,但是在通常的JDK/JRE實現中,擴展類加載器getParent()都只能返回null。
public final ClassLoader getParent()
擴展類加載器(Extension or Ext Class-Loader),負責加載我們放到jre/lib/ext目錄下面的jar包,這就是所謂的extension機制。該目錄也可以通過設置“java.ext.dirs”來覆蓋
java -Djava.ext.dirs=your_ext_dir HelloWorld
應用類加載器(Application or App Class-Loader),就是加載我們最熟悉的classpath的內容。這里有一個容易混淆的概念,系統(System)類加載器,通常來說,其默認就是JDK內建的應用類加載器,但是它同樣是可能修改的,比如:
java -Djava.system.class.loader=com.yourcorp.YourClassLoader HelloWorld
如果我們指定了這個參數,JDK內建的應用類加載器就會成為定制加載器的父親,這種方式通常用在類似需要改變雙親委派模式的場景。
具體參考下圖:
談到類加載一個躲不開的話題就是“雙親委派模型”,簡單說就是當類加載器(Class-Loader)試圖加載某個類型的時候,除非父加載器找不到相應的類型,否則盡量將這個任務代理給當前加載器的父加載器去做。
參考上面這個結構圖就很容易理解了。試想,如果不同類加載器都自己加載需要的某個類型,那么就會出現多次重復加載,完全是種浪費。
通常類加載器機制有三個基本特征:
雙親委派模型。但不是所有類加載都遵守這個模型,有的時候,啟動類加載器所加載的類型,是可能要加載用戶代碼的。比如JDK內部的ServiceProvider/ServiceLoader機制,用戶可以在標準API框架上,提供自己的實現,JDK也需要提供些默認的參考實現。例如,Java中JNDI、JDBC、文件系統、Cipher等很多方面,都是利用的這種機制,這種情況就不會用雙親委派模型去加載,而是利用所謂的上下文加載器。
可見性。子加載器可以訪問父加載器加載的類型,但是反過來是不允許的。不然,因為缺少必要的隔離,我們就沒有辦法利用類加載器去實現容器的邏輯。
單一性。由于父加載器的類型對于子加載器是可見的,所以父加載器中加載過的類型,就不會在子加載器中重復加載。但是注意,類加載器“鄰居”間,同一類型仍然可以被加載多次,因為互相不可見。
“java類加載過程分為哪些步驟”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。