淺談Java類型裝載、鏈接與初始化--轉自https://blog.csdn.net/lincolnmi/article/details/50538016

類型裝載、鏈接與初始化

Java虛擬機經過裝載、鏈接和初始化一個Java類型,使該類型能夠被正在運行的Java程序所使用。其中裝載就是把二進制形式的Java class文件讀入Java虛擬機中去;鏈接把讀入虛擬機的二進制形式的Java class文件合併到虛擬機的運行時的狀態中去。鏈接能夠分爲三個子步驟,驗證,準備和初始化。驗證步驟確保了Java類型數據格式正確而且適於Java虛擬機使用。準備爲該類型分配內存(如爲類變量分配內存)。解析負責將常量池中的符合引用轉換爲直接引用,虛擬機的實現能夠推遲解析這一步驟。即當運行中的程序真正使用某個符號的時候再去解析它。(符號引用變爲直接引用)。初始化爲類變量賦以適當的初始值。 
下面就這5個步驟進行詳細的解析:java

裝載

裝載階段由三個動做完成程序員

  1. 經過該類型的徹底限定名,產生一個表明該類型的二進制數據流。 
    該二進制數據流能夠遵循class文件格式,也能夠遵照其餘數據格式。全部虛擬機必須能識別Java class文件格式,可是個別的也能夠識別其餘二進制格式。 
    Java虛擬機並未規定該二進制數據流如何產生,所以下面列出了可能產生二進制數據的方式: 
    從本地文件系統裝載class文件; 
    從網絡下載一個class文件; 
    從ZIP,JAR,CAB中提取class文件; 
    從專有數據庫中提取class文件; 
    將Java源文件編譯爲class文件; 
    使用上述方法,可是產生非class文件格式的二進制文件格式
  2. 解析這個二進制數據流爲方法區的內部數據結構。
  3. 建立一個表示該類型的java.lang.class類的實例。

裝載的最終目的就是建立java.lang.class的實例對象,解析二進制數據流爲方法區的內部數據結構,並在堆上面創建一個Class對象。Class對象是Java程序與內部數據結構之間的接口。數據庫

Java類型要麼被啓動類裝載器裝載,要麼被用戶自定義的類加載器加載。 
類加載器並非在某個類型首次主動使用的時候加載它。能夠提早預判,預加載這個類型。若是預加載的時候出現問題,不會當即報錯。直到程序主動使用該類才報錯。也就是說程序已知不主動使用該類類型,類加載器就一直不報錯。網絡

裝載時會作兩項檢查,雖然在驗證階段以前進行,但邏輯上屬於驗證階段。數據結構

  1. 驗證class文件格式是否正確,如魔數,每一個部分在正確位置,正確的長度,文件的長度不是太長或過短等。 保證正式解析二進制class文件時候,不會形成虛擬機的崩潰。
  2. 確保每一個除Object以外每一個類都有一個超類,加載某個類的時候,確保該類的全部超類必須加載。

驗證

類型被加載後,虛擬機開始鏈接,鏈接第一步是驗證,即確認它是否符合Java語言的語義,而且不會危及虛擬機的完整性。 
驗證的時機和方式,不一樣虛擬機有着不一樣的實現。虛擬機規範只是規定了虛擬機在驗證過程當中能夠拋出的異常以及在何種狀況下必須拋出它們。 
驗證階段每每會驗證以下內容:性能

  1. 檢查final的類不擁有子類
  2. 檢查final方法不能被覆蓋
  3. 確保類型和超類型之間沒有不兼容的方法申明(好比兩個方法簽名徹底同樣,但返回類型不一樣)
  4. 檢查全部的常量池入口相互之間保持一致(好比CONSTANT_String_info入口的string_index項目必須是一個CONSTANT_Utf8_info入口的索引)
  5. 檢查常量池中全部的特殊字符串(類名,字段名,方法名,字段描述符和方法描述符)是否符合格式
  6. 檢查字節碼的完整性

上述任務最複雜的是最後一個,檢查字節碼的完整性。不能由於挑戰指令超出了方法末尾致使了虛擬機崩潰。虛擬機必須在驗證階段檢查出這樣的字節碼是非法的,從而拋出一個錯誤。 
不過虛擬機規範並未規定字節碼驗證必須在驗證階段執行,也能夠在執行每條語句的時候單獨進行驗證。Java虛擬機指令集當初設定目標是字節碼流一次性使用數據流分析器進行驗證。不過運行時候進行驗證,會使得Java程序運行速度提升。當使用數據流分析器進行字節碼驗證時候,可能爲了確保符合Java語言的語義而裝載其餘的類。好比加載了Float類,必須還加載其父類Number保證其不是一個final類。.net

驗證階段以後可能還會進行一項檢查,那就是符號引用的驗證。虛擬機在將符號引用替換爲直接引用,須要檢查該元素的存在性以及訪問的權限。邏輯上屬於驗證,但每每在解析階段發生。指針

準備

在準備階段,Java虛擬機爲類變量分配內存,並設置默認的初始值。在正式初始化階段以前,類變量都沒有被正式初始化爲真正的初始值。 
準備階段,乾的另一件事就是可能爲一些數據結構分配內存,進而提升程序運行的性能。好比方法表的創建,它包含了指向類中每個方法包括從超類繼承方法的指針。從而能夠在執行繼承方法時候不須要搜索超類。對象

解析

解析過程就是在類型的常量池中尋找類、接口、自動和方法的符合引用,把這些符號引用變成直接引用的過程。還記得邏輯上屬於驗證的符合引用的驗證麼?解析何時執行是虛擬機本身決定的,能夠在初始化階段後面執行。blog

初始化

初始化階段爲類變量賦予正確的初始值。在準備階段,類變量被賦予了默認值,在這一階段,類變量被賦予正確的初始值,即程序員但願這個類變量具有的起始值。 
具體的初始化過程參見下一篇博客《淺談類加載的初始化階段

相關文章
相關標籤/搜索