類加載的執行過程

前言一個Java文件從編碼完成到最終執行,通常主要包括兩個過程java

編譯安全

運行網絡

編譯,即把咱們寫好的java文件,經過javac命令編譯成字節碼,也就是咱們常說的.class文件。編碼

運行,則是把編譯聲稱的.class文件交給Java虛擬機(JVM)執行。加密

而咱們所說的類加載過程便是指JVM虛擬機把.class文件中類信息加載進內存,並進行解析生成對應的class對象的過程。代理

舉個通俗點的例子來講,JVM在執行某段代碼時,遇到了class A, 然而此時內存中並無class A的相關信息,因而JVM就會到相應的class文件中去尋找class A的類信息,並加載進內存中,這就是咱們所說的類加載過程。指針

因而可知,JVM不是一開始就把全部的類都加載進內存中,而是隻有第一次遇到某個須要運行的類時纔會加載,且只加載一次。對象

類加載
類加載的過程主要分爲三個部分:繼承

加載內存

連接

初始化

而連接又能夠細分爲三個小部分:

驗證

準備

解析

加載

簡單來講,加載指的是把class字節碼文件從各個來源經過類加載器裝載入內存中。

這裏有兩個重點:

字節碼來源。通常的加載來源包括從本地路徑下編譯生成的.class文件,從jar包中的.class文件,從遠程網絡,以及動態代理實時編譯

類加載器。通常包括啓動類加載器,擴展類加載器,應用類加載器,以及用戶的自定義類加載器。

注:爲何會有自定義類加載器?

一方面是因爲java代碼很容易被反編譯,若是須要對本身的代碼加密的話,能夠對編譯後的代碼進行加密,而後再經過實現本身的自定義類加載器進行解密,最後再加載。

另外一方面也有可能從非標準的來源加載代碼,好比從網絡來源,那就須要本身實現一個類加載器,從指定源進行加載。

驗證
主要是爲了保證加載進來的字節流符合虛擬機規範,不會形成安全錯誤。

包括對於文件格式的驗證,好比常量中是否有不被支持的常量?文件中是否有不規範的或者附加的其餘信息?

對於元數據的驗證,好比該類是否繼承了被final修飾的類?類中的字段,方法是否與父類衝突?是否出現了不合理的重載?

對於字節碼的驗證,保證程序語義的合理性,好比要保證類型轉換的合理性。

對於符號引用的驗證,好比校驗符號引用中經過全限定名是否可以找到對應的類?校驗符號引用中的訪問性(private,public等)是否可被當前類訪問?

準備
主要是爲類變量(注意,不是實例變量)分配內存,而且賦予初值。

特別須要注意,初值,不是代碼中具體寫的初始化的值,而是Java虛擬機根據不一樣變量類型的默認初始值。

好比8種基本類型的初值,默認爲0;引用類型的初值則爲null;常量的初值即爲代碼中設置的值,final static tmp = 456, 那麼該階段tmp的初值就是456

解析
將常量池內的符號引用替換爲直接引用的過程。

兩個重點:

符號引用。即一個字符串,可是這個字符串給出了一些可以惟一性識別一個方法,一個變量,一個類的相關信息。

直接引用。能夠理解爲一個內存地址,或者一個偏移量。好比類方法,類變量的直接引用是指向方法區的指針;而實例方法,實例變量的直接引用則是從實例的頭指針開始算起到這個實例變量位置的偏移量

舉個例子來講,如今調用方法hello(),這個方法的地址是1234567,那麼hello就是符號引用,1234567就是直接引用。

在解析階段,虛擬機會把全部的類名,方法名,字段名這些符號引用替換爲具體的內存地址或偏移量,也就是直接引用。

初始化
這個階段主要是對類變量初始化,是執行類構造器的過程。

換句話說,只對static修飾的變量或語句進行初始化。

若是初始化一個類的時候,其父類還沒有初始化,則優先初始化其父類。

若是同時包含多個靜態變量和靜態代碼塊,則按照自上而下的順序依次執行。

相關文章
相關標籤/搜索