JAVA類加載機制

概述

虛擬機把描述類的數(shù)據(jù)從Class文件加載到內(nèi)存中,并對數(shù)據(jù)進行驗證请祖,準備订歪,解析,初始化的一個過程肆捕,最終是可以被虛擬機直接使用的java類型刷晋,這就是類加載的一個簡單的過程。
Java中的類加載是在運行時加載,這樣會比較的消耗性能眼虱,但是正是在運行時加載使得java擁有很好的靈活性和可擴展性喻奥。

類加載的時機

類從被加載到內(nèi)存中開始,到卸載出內(nèi)存為止捏悬。它的生命周期總共七個階段:加載---->驗證---->準備---->解析---->初始化---->使用---->卸載撞蚕。其中解析這個過程是不確定的,它可能會在初始化后之后过牙,這是為了使java支持運行時的綁定甥厦。

  • new ,getstatic寇钉,putstatic刀疙,invokestatic這四條指令時會觸發(fā)初始化的操作。
  • new是new一個新的對象時會觸發(fā)初始化摧莽。
  • getstatic是獲取靜態(tài)字段時會觸發(fā)庙洼。
  • putstatic是設(shè)置靜態(tài)字段時會觸發(fā)。
  • invokestatic是調(diào)用另一個類的靜態(tài)方法的時候镊辕。
    PS:需要注意的是getstatic和putstatic被final修飾的油够,在編譯期就放入到常量池中是不會觸發(fā)的。
  • 使用java.lang.reflect的包方法對類進行反射調(diào)用時征懈,如果類沒有初始化就需要進行初始的操作石咬。
  • 子類進行初始化時需要對父類先進行初始。
  • java啟動時需要的啟動主類卖哎,程序的入口鬼悠。該類就需要進行初始化。
  • 使用JDK1.7的動態(tài)語言支持時亏娜,如果一個java.lang.invoke.Methondhandle實例最后解析結(jié)果REF_getStatic焕窝,REF_putStatic,REF_invokeStatic的方法句柄维贺,如果沒有進行初始化時會觸發(fā)初始化它掂。
    PS:接口的初始化和類初始化不同,接口初始化只和類初始化的子類初始化是需要父類先進行初始化溯泣,而且并不是接口父類中的所有都是會初始化虐秋。

加載

加載是類加載中前面提到的其中的一個過程。類加載的基本過程:

  • 通過全限定類名加載二進制流垃沦。
  • 將二進制流代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)換方法區(qū)中運行時的數(shù)據(jù)結(jié)構(gòu)客给。
  • 在內(nèi)存中生成java.lang.Class對象,將這個作為該方法區(qū)這個類中各種數(shù)據(jù)的一個入口肢簿。

加載分為數(shù)組類加載過程和非數(shù)組類的加載過程靶剑。java的數(shù)組類的加載過程其實是有虛擬機直接加載的但是數(shù)組中的類型需要類加載機制加載:

  • 非數(shù)組類加載機制:可控性強既可以有系統(tǒng)類加載器進行加載又可以由用戶自定義的類加載器進行加載蜻拨。(重寫一個類加載器的loadClass()方法)。
  • 數(shù)組類型的加載機制:數(shù)組類型的加載機制如果是引用類型抬虽,就使用遞歸進行加載官觅,并且會在加載的類型上加入一個標志。如果是非引用類型則會把標志與引導(dǎo)類加載器關(guān)聯(lián)阐污。

ps:數(shù)組類的可見性與它組件的可見性是相同的休涤,如果組件類型不是引用類型的可見性一般設(shè)置為public。
類加載完成會有一個連接笛辟,可能在沒完成加載就開始連接功氨,雖然如此但是該順序是一定的。

驗證

驗證的主要目的是保證加載進來的Class文件的字節(jié)流包含的信息符合虛擬機的當(dāng)前的要求手幢,不會有危害自身的數(shù)據(jù)存在捷凄。
Java是相對C++語言是安全的語言,例如它有C++不具有的數(shù)組越界的檢查围来。這本身就是對自身安全的一一種保護跺涤。驗證階段是Java非常重要的一個階段,它會直接的保證應(yīng)用是否會被惡意入侵的一道重要的防線监透,越是嚴謹?shù)尿炞C機制越安全桶错。驗證的四個階段文件格式驗證-->元數(shù)據(jù)驗證-->字節(jié)碼驗證-->符號引用驗證。

  • 文件格式驗證:主要驗證字節(jié)流是否符合Class文件格式規(guī)范胀蛮,并且能被當(dāng)前的虛擬機加載處理院刁。
  • 是否以魔數(shù)開頭。
  • 主粪狼,次版本號是否在當(dāng)前虛擬機處理的范圍之內(nèi)退腥。
  • 常量池中是否有不被支持的常量類型。
  • 指向常量的中的索引值是否存在不存在的常量或不符合類型的常量再榄。
  • CONSTANT_Utf8_info型的常量中有不符合utf8格式的編碼數(shù)據(jù)狡刘。
    還有大其它的驗證這里就不一一的列舉。
  • 元數(shù)據(jù)驗證:對字節(jié)碼描述的信息進行語義的分析困鸥,分析是否符合java的語言語法的規(guī)范嗅蔬。
  • 字節(jié)碼驗證:最重要的驗證環(huán)節(jié),分析數(shù)據(jù)流和控制窝革,確定語義是合法的郑口,符合邏輯的似袁。主要的針對元數(shù)據(jù)驗證后對方法體的驗證吞歼。保證類方法在運行時不會有危害出現(xiàn)扶关。
  • 符號引用驗證:主要是針對符號引用轉(zhuǎn)換為直接引用的時候佩微,是會延伸到第三解析階段削饵,主要去確定訪問類型等涉及到引用的情況加叁,主要是要保證引用一定會被訪問到扮休,不會出現(xiàn)類等無法訪問的問題。

雖然驗證很重要但是并不是必須的階段厢拭。當(dāng)然大量重復(fù)的驗證會相當(dāng)?shù)幕ㄙM性能和時間的兰英。
準備


準備階段主要是類變量進行分配內(nèi)存和數(shù)據(jù)的初始化階段,所謂的初始化并不是你編碼時所定義的變量值供鸠。例如:

public static int age = 20;

數(shù)據(jù)的初始化并不會將它初始化為20畦贸,而是初始化為0,系統(tǒng)有一套自己的初始化值楞捂。如下圖:

數(shù)據(jù)類型 零值
int 0
long 0L
short 0
char '\u0000'
byte 0
boolean false
float 0.0f
double 0.0d
reference null

當(dāng)然會有特殊的情況薄坏,如下面的代碼:

public static final int value = 20;

這種情況是類的字段時存在ConstantValue屬性所指定的字段。用final修飾后出現(xiàn)該屬性寨闹,加初始化時會直接的使用ConstantValue的屬性值胶坠,所以會初始化為20。
解析


解析是將常量池中的符號引用轉(zhuǎn)化為直接引用的過程繁堡,還記得前面驗證階段時出現(xiàn)的符號引用驗證嗎沈善?就是對該階段的驗證。

  • 符號引用:符號引用是以一組符號來描述所引用的目標椭蹄,符號可以是任何的字面形式的字面量闻牡,只要不會出現(xiàn)沖突能夠定位到就行。布局和內(nèi)存無關(guān)塑娇。
  • 直接引用:是指向目標的指針澈侠,偏移量或者能夠直接定位的句柄。該引用是和內(nèi)存中的而布局有關(guān)的埋酬,并且一定加載進來的哨啃。

虛擬機可能會多次的進行解析。解析主要的對類写妥,接口拳球,字段,類方法珍特,接口方法祝峻,方法類型,方法句柄和調(diào)用點限定符引用進行扎筒。這七種解析有細節(jié)上的不同莱找,主要的思想是通過限定性類名找到解析的類型進行解析。主要的是會分為數(shù)組類型嗜桌,非數(shù)組類型存在一個直接進行解析的過程奥溺。在過程還有從下上的匹配查找(主要出現(xiàn)在有繼承,接口的情況下)骨宠。

初始化

初始化算是類加載過程的最后一個階段浮定,在這個階段在是真正的開始有java代碼主導(dǎo)相满。大家應(yīng)該記得在準備階段已經(jīng)進行過一次賦值,但是只是系統(tǒng)的默認賦值(ConstantValue的例外情況)桦卒。初始化是執(zhí)行<clinit>的過程立美。

  • <clinit>的主要是查找static模塊,用戶自定義類變量的賦值方灾,該順序是由文件中的順序界定的建蹄。加載過程存在的是父類的一定會比子類先進行加載到,因為會保證子類的<clinit>加載完成時父類的<clinit>一定會加載完成裕偿。所有就像大家所知道的java.lang.object一定會是虛擬機中第一個加載完成的躲撰。
  • <clinit>在接口中的加載是不同的它是不存在靜態(tài)塊的,接口中也是會有賦值進行的击费,但是接口中的是在需要用到才會去進行加載的拢蛋。
  • 允許在定義之前進行賦值的操作,但是不允許使用蔫巩,如下:
public class A{
  static{
          s = 20;
          //system.out.printf(s); 
          上面注釋的這句話時會出現(xiàn)錯誤的谆棱;
  }
  static int s = 10;
}  
  • 虛擬機會保證在多線程的環(huán)境下進行加鎖,保證正確執(zhí)行圆仔。如果有多個進行加載一個會保證只有一個去加載垃瞧,其他的會進去阻塞等待中。同一個類只會加載一次坪郭,就算多個進入阻塞也不會重新喚醒个从。

類加載器

  • 類與類加載器:一個類的相同判斷條件大家都知道,但是如果不是由同一個類加載器加載出來的歪沃,就算是看起來相同的也是出現(xiàn)false的嗦锐。
  • 三大類加載器:
    • 啟動類加載器
    • 擴展類加載器
    • 應(yīng)用程序類加載器
  • 雙親委托機制:


    雙器委托機制

    雙親委托機制是當(dāng)一個類進入加載時,子加載器不會自己嘗試去加載沪曙,而是將其發(fā)送到它的父加載器中加載奕污,以此類推直到達到最后的加載器,只有當(dāng)父加載器不能進行加載是會發(fā)送到子加載器中液走,子加載此時才會嘗試去加載碳默。

public Class<?> loadClass(String name)throws ClassNotFoundException {
            return loadClass(name, false);
    }
 
    protected synchronized Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException {
            // 首先判斷該類型是否已經(jīng)被加載
            Class c = findLoadedClass(name);
            if (c == null) {
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                    //如果不存在父類加載器,就檢查是否是由啟動類加載器加載的類缘眶,通過調(diào)用本地方法native Class findBootstrapClass(String name)
                        c = findBootstrapClass0(name);
                    }
                } catch (ClassNotFoundException e) {
                 // 如果父類加載器和啟動類加載器都不能完成加載任務(wù)嘱根,才調(diào)用自身的加載功能
                    c = findClass(name);
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
  • 雙親委托機制的破壞
  • 1.2版本為了向前兼容1.0版本
  • 本身模型的問題,基礎(chǔ)類要調(diào)用用戶類而出現(xiàn)的沖突巷懈。通過設(shè)置線程上下文類加載器该抒,如果出現(xiàn)上面這種情況,通過上下文類加載器去加載所需的類砸喻。
  • 用戶對動態(tài)性的追求柔逼,出現(xiàn)沒一個模塊都有自己的類加載器,如果需要更換時連同類加載器一同換掉割岛。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末愉适,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子癣漆,更是在濱河造成了極大的恐慌维咸,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惠爽,死亡現(xiàn)場離奇詭異癌蓖,居然都是意外死亡,警方通過查閱死者的電腦和手機婚肆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門租副,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人较性,你說我怎么就攤上這事用僧。” “怎么了赞咙?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵责循,是天一觀的道長。 經(jīng)常有香客問我攀操,道長院仿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任速和,我火速辦了婚禮歹垫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘颠放。我一直安慰自己县钥,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布慈迈。 她就那樣靜靜地躺著若贮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪痒留。 梳的紋絲不亂的頭發(fā)上谴麦,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天,我揣著相機與錄音伸头,去河邊找鬼匾效。 笑死,一個胖子當(dāng)著我的面吹牛恤磷,可吹牛的內(nèi)容都是我干的面哼。 我是一名探鬼主播野宜,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼魔策!你這毒婦竟也來了匈子?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤闯袒,失蹤者是張志新(化名)和其女友劉穎虎敦,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體政敢,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡其徙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了喷户。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唾那。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖褪尝,靈堂內(nèi)的尸體忽然破棺而出通贞,到底是詐尸還是另有隱情,我是刑警寧澤恼五,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布昌罩,位于F島的核電站,受9級特大地震影響灾馒,放射性物質(zhì)發(fā)生泄漏茎用。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一睬罗、第九天 我趴在偏房一處隱蔽的房頂上張望轨功。 院中可真熱鬧,春花似錦容达、人聲如沸古涧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽羡滑。三九已至,卻和暖如春算芯,著一層夾襖步出監(jiān)牢的瞬間柒昏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工熙揍, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留职祷,地道東北人。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像有梆,于是被迫代替她去往敵國和親是尖。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Java的核心是 JVM 泥耀,了解并熟悉JVM對于我們理解Java語言非常重要饺汹。 一、類加載機制 當(dāng)程序主動使用某個...
    年少懵懂丶流年夢閱讀 1,088評論 2 15
  • 1.虛擬機如何加載這些Class文件?(類加載的過程)2.Class文件中的信息進入到虛擬機后會發(fā)生什么變化? J...
    wangcanfeng閱讀 231評論 0 0
  • 類加載器簡單來說是用來加載 Java 類到 Java 虛擬機中的爆袍。Java 虛擬機使用 Java 類的方式如下:J...
    愛情小傻蛋閱讀 731評論 2 11
  • 一、類加載機制 1.定義: 把描述類的數(shù)據(jù)從Class文件加載到內(nèi)存作郭,并對數(shù)據(jù)進行校驗陨囊、轉(zhuǎn)換解析和初始化,最終形成...
    Ruheng閱讀 2,333評論 6 36
  • 虛擬機類加載機制 1. 類加載的時機1.1 類從被加載到虛擬機內(nèi)存開始夹攒,到卸載出內(nèi)存為止蜘醋,他的整個生命周期包括: ...
    天空在微笑閱讀 197評論 0 0