JAVA類加載器總結

一個java類在系統中要面臨編譯和運行兩種過程
編譯是指將java文件通過javac命令轉換爲字節碼生成 .class文件
而運行是將.class文件交給jvm虛擬機運行。
類的加載就是運行的初期,jvm加載.class文件,解析生成對應的class對象,並把相關類的信息加載到內存裏。

jvm是加載類是按需加載,如果得到一個類,經過在自己的class文件中找不到相關的信息,他纔會加載

類的加載過程

在這裏插入圖片描述

加載

類的加載就是將編譯得到的.class字節碼文件通過類加載器產生一個Class對象加入到內存中

鏈接

  • 驗證:目的在於確保Class文件的字節流中包含信息符合當前虛擬機要求,不會危害虛擬機自身安全。主要包括四種驗證

    • 文件格式驗證: 比如常量中是否有不被支持的常量?文件中是否有不規範的或者附加的其他信息
    • 元數據驗證:比如該類是否繼承了被final修飾的類?類中的字段,方法是否與父類衝突?是否出現了不合理的重載?
    • 字節碼驗證:保證程序語義的合理性,比如要保證類型轉換的合理性。
    • 符號引用驗證:比如校驗符號引用中通過全限定名是否能夠找到對應的類?校驗符號引用中的訪問性(private,public等)是否可被當前類訪問?
  • 準備:

    爲類變量也就是static修飾變量分配內存並賦予初值,這裏的初值並不是實際的變量,而是規定的初值,比如比如8種基本類型的初值,默認爲0;引用類型的初值則爲null,這裏的static變量不包含final static 修飾的常量,因爲final修飾的常量的早在編譯的時候就確定了。
  • 解析

    將主要將常量池中的符號引用替換爲直接引用的過程。符號引用就是一組符號來描述目標,可以是任何字面量,而直接引用就是直接指向目標的指針、相對偏移量或一個間接定位到目標的句柄。符號引用。即一個字符串,但是這個字符串給出了一些能夠唯一性識別一個方法,一個變量,一個類的相關信息。直接引用。可以理解爲一個內存地址,或者一個偏移量。比如類方法,類變量的直接引用是指向方法區的指針;而實例方法,實例變量的直接引用則是從實例的頭指針開始算起到這個實例變量位置的偏移量
    舉個例子來說,現在調用方法hello(),這個方法的地址是1234567,那麼hello就是符號引用,1234567就是直接引用。
    在解析階段,虛擬機會把所有的類名,方法名,字段名這些符號引用替換爲具體的內存地址或偏移量,也就是直接引用。

初始化

這個階段主要是對類變量初始化,是執行類構造器的過程。
換句話說,只對static修飾的變量或語句進行初始化。
如果初始化一個類的時候,其父類尚未初始化,則優先初始化其父類。
如果同時包含多個靜態變量和靜態代碼塊,則按照自上而下的順序依次執行。
執行靜態初始化器和靜態初始化成員變量(如前面只初始化了默認值的static變量將會在這個階段賦值,成員變量也將被初始化

類加載器

以上就是類加載的整個過程,接下來主要看一看,類加載過程的加載過程和加載器的相關:

類的加載指的是將類的.class文件中的二進制數據讀入到內存中,將其放在運行時數據區的方

法區內,然後在堆區創建一個這個類的java.lang.Class對象,用來封裝類在方法區類的對象。

JVM設計者把類加載階段中的“通過’類全名’來獲取定義此類的二進制字節流”這個動作放到Java

虛擬機外部去實現,以便讓應用程序自己決定如何去獲取所需要的類。實現這個動作的代碼模

塊稱爲“類加載器”

(類加載器的任務是根據一個類的全限定名來讀取此類的二進制字節流到JVM中,然後轉換爲一個與目標類對應的java.lang.Class對象實例,在虛擬機提供了3種類加載器,引導

(Bootstrap)類加載器、擴展(Extension)類加載器、系統(System)類加載器(也稱應用類加載器))

從jvm的角度看類加載器分爲兩種,一種是啓動類加載器BootstrapClassLoader,負責加載jvm自身所用的類庫,java程序不能直接利用,另一種是其他類加載器,都是在jvm外面通過java語言實現的,而且全部繼承了java.lang.ClassLoader

——————

從程序員的角度看類加載器分爲下面三種:

啓動類加載器(Bootstrap ClassLoader):

啓動類加載器主要加載的是JVM自身需要的類,這個類加載使用C++語言實現

的,是虛擬機自身的一部分,它負責將 <JAVA_HOME>/lib路徑下的核心類庫或-

Xbootclasspath參數指定的路徑下的jar包加載到內存中,注意必由於虛擬機是按

照文件名識別加載jar包的,如rt.jar,如果文件名不被虛擬機識別,即使把jar包丟

到lib目錄下也是沒有作用的(出於安全考慮,Bootstrap啓動類加載器只加載包名

爲java、javax、sun等開頭的類)。

擴展類加載器(Extension ClassLoader):

擴展類加載器是指Sun公司(已被Oracle收購)實現的

sun.misc.Launcher$ExtClassLoader類,由Java語言實現的,是Launcher的靜態

內部類,它負責加載<JAVA_HOME>/lib/ext目錄下或者由系統變量-Djava.ext.dir指

定位路徑中的類庫,開發者可以直接使用標準擴展類加載器。

應用程序類加載器(Application ClassLoader):

該類加載器也稱爲系統類加載器,它負責加載用戶類路徑(Classpath)上所指定

的類庫,開發者可以直接使用該類加載器,如果應用程序中沒有自定義過自己的

類加載器,一般情況下這個就是程序中默認的類加載器。

也稱系統加載器是指 Sun公司實現的sun.misc.Launcher$AppClassLoader。

它負責加載系統類路徑java -classpath或-D java.class.path 指定路徑下的類庫

雙親委派模型

在這裏插入圖片描述
(有些醜)

雙親委派就是

雙親委派模型的工作過程爲:如果一個類加載器收到了類加載的請求,它首先不會自己去嘗試加載這個類,而是把這個請求委派給父類加載器去完成,每一個層次的加載器都是如此,因此所有的類加載請求都會傳給頂層的啓動類加載器,只有當父加載器反饋自己無法完成該加載請求(該加載器的搜索範圍中沒有找到對應的類)時,子加載器纔會嘗試自己去加載。

發佈了124 篇原創文章 · 獲贊 9 · 訪問量 2478
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章