成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

java類的加載過程

ormsf / 1393人閱讀

摘要:一類加載的過程虛擬機加載類主要有五個過程加載驗證準備解析和初始化。初始化在虛擬機中嚴格規(guī)定需要對類進行初始化的,有下面五種情況遇到,,或者這條字節(jié)碼指令時。

在<深入理解Java虛擬機-周志明>這本書里面,在講到類初始化的五種情況時,提及了一個比較有趣的事情。先來看看下面的代碼

public class SubClass {
    static{
        System.err.println("I m your son");
    }
    public static final int name = 111;
}

這個時候如果調(diào)用SubClass.name,是根本不會觸發(fā)SubClass初始化的(這里是因為name是一個常量,和下面的例子不一樣,如果這里把final去掉,是會觸發(fā)Subclass的初始化的,因為對于靜態(tài)字段而言,如果靜態(tài)字段被引用,就會調(diào)用getstatic指令和putstatic指令,那么自然就會引發(fā)類的初始化,詳情看下面關(guān)于觸發(fā)類初始化的五種情況)。再來看看另一種情況;

public class SuperClass {

    static{
        System.err.println("I am your father");
    }
    public static int value = 123;
}
public class SubClass extends SuperClass{
    static{
        System.err.println("I m your son");
    }
}

這個時候如果調(diào)用SubClass.value(靜態(tài)字段和靜態(tài)方法是可以繼承但是無法被覆蓋,所以這里調(diào)用value,只會導致直接定義這個靜態(tài)變量的類被初始化),同樣也是不會使得SubClass這個類進行初始化。那么問題來了,到底類在什么時候會進行初始化,類的初始化順序到底是怎樣的?讓我們接著往下看。

一. 類加載的過程
虛擬機加載類主要有五個過程:加載、驗證、準備、解析和初始化。

加載:加載是“類加載”的一個過程,希望讀者沒有混淆這兩個概念。

在這個過程虛擬機主要完成三件事,
? 通過一個類的全限定名___[解釋全限定名]___來獲取此類的二進制字節(jié)流,這點上,虛擬機并沒有指明要從哪里獲取類的二進制字節(jié)流,因此發(fā)展出了很多不一樣的加載方式。比如jar,zip等壓縮包中加載,從網(wǎng)絡(luò)獲取[如Applet],或者由其他文件生成[如從JSP生成]。
? 將字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu)。
? 在Java堆[這個沒有強制規(guī)定,比如HotSpot則選擇在方法區(qū)中生成這個對象]中生成一個代表這個類的java.lang.Class對象,作為程序訪問方法區(qū)中的各種數(shù)據(jù)的外部入口[也就是說當常量池表中的數(shù)據(jù)被轉(zhuǎn)換成運行時數(shù)據(jù)結(jié)構(gòu)的時候,實際上[堆/方法區(qū)]有一個Class對象的實例可以訪問到方法區(qū)的各類數(shù)據(jù),包括常量池表,代碼等]。
如果加載對象是普通的類或者接口(統(tǒng)稱為C),則是通過類加載器(L)去加載C的二進制表示來創(chuàng)建。但是如果加載的是數(shù)組類,那情況就有所不同了,數(shù)組類本身不通過類加載器創(chuàng)建,它是由Java虛擬機直接創(chuàng)建的。但是數(shù)組類內(nèi)部的元素類型最終還是要靠類加載器去加載。[后續(xù)可以添加類加載器的詳細解釋]

驗證

驗證是鏈接階段的第一步,這一階段的目的是為了確保Class文件的字節(jié)流中包含的信息符合當前虛擬機的要求,并且不會危害虛擬機本身的安全。驗證大致上有以下4個過程:
1) 文件格式驗證:
a) 檢查魔數(shù),主、次版本號是否在當前虛擬機處理范圍。
b) 常量池的常量是否不被支持[通過檢查tag],指向常量的各種索引值中是否有指向不存在的常量或不符合類型的常量。
c) CONSTANT_Utf8_info類型的常量中是否有不符合UTF8編碼的數(shù)據(jù)。
d) Class文件中各個部分及文件本身是否有被刪除或者附加其他信息等等。
這個節(jié)點的主要目的是保證輸入的字節(jié)流能被正確的解析并存儲于方法區(qū)內(nèi),格式上符合描述一個java類型信息的要求。這個階段是基于二進制流,只要通過了這個階段的驗證,字節(jié)流才會進入內(nèi)存的方法區(qū)中存儲。所以后續(xù)的三個階段基于方法區(qū)的存儲結(jié)構(gòu)進行的,不會再直接操作字節(jié)流。
2) 元數(shù)據(jù)驗證:這個階段是對字節(jié)碼描述的信息進行語義分析,以保證其描述的信息符合Java語言規(guī)范的要求。主要驗證包括以下幾點:
a) 這個類是否有父類(除了java.lang.Object外,所有的類都應(yīng)該有父類)。
b) 這個類的父類是否繼承了不允許被繼承的類(被final修飾的類)。
c) 如果這個類不是抽象類,那么應(yīng)該實現(xiàn)其父類或接口中要求實現(xiàn)的方法。
d) 類中的字段,方法是否與父類相矛盾(例如覆蓋了父類的final字段,或者出現(xiàn)不符合規(guī)則的方法重載)。
這個階段主要目的是對類的元數(shù)據(jù)信息進行語義校驗,保證不存在不符合Java規(guī)范的元數(shù)據(jù)信息。
3) 字節(jié)碼驗證:
4) 符號引用驗證:

準備

準備階段是正式為類變量分配內(nèi)存并設(shè)置類變量的初始值階段,這些變量所使用的內(nèi)存都將在方法區(qū)中分配。這里有幾個值得注意的點:
1) 這里初始化的僅僅是類變量(被static修飾的變量)的初始化,并不包括實例變量。實例變量將會在對象實例化的時候隨著對象一起分配在java堆中。
2) 這里所說的初始值,通常是數(shù)據(jù)類型的零值,舉個例子:
public static int value = 123;
這句代碼中,value在準備階段的初始值為0,而不是123,因為這個時候還沒開始執(zhí)行任何的java方法。而把value的值置為123的putstatic指令是程序被編譯后,存放在類構(gòu)造器()方法中的。所以value置為123是在初始化[第五階段]階段才會執(zhí)行。[還有一些其他類型的零值,可以參考虛擬機規(guī)范]
當然,上述情況也有例外的地方,如果類字段的字段屬性表(參考class文件中的屬性數(shù)據(jù)結(jié)構(gòu))中存在ConstatntValue[即同時被final和static修飾]屬性,那么在準備階段,變量value就會被初始化為ConstantValue屬性所指定的值,例如上述變量中,編譯時javac將會為value生成的ConstantValue屬性,在準備階段虛擬機就會根據(jù)ConstantValue屬性而將value賦值為123。

解析

解析階段就是虛擬機將常量池內(nèi)的符號引用[使用一組描述符來描述所引用的目標,符可以是任意形式的字面量,只要使用時能無歧義的定位到目標即可。符號引用與虛擬機實現(xiàn)的內(nèi)存布局無關(guān),引用的目標并不一定已經(jīng)加載到內(nèi)存中]替換為直接引用[直接引用可以是直接指向目標的指針,相對偏移量或者一個能間接定位到目標的句柄。直接引用與內(nèi)存的布局有關(guān),如果有了直接引用,則目標一定存在]的過程,符號引用在Class文件內(nèi)的常量池中以CONSTANT_Fieldref_info,CONSTANT_Class_info,CONSTANT_Methodref_info等類型出現(xiàn)。那么,解析階段中的直接引用于符號引用又有什么關(guān)聯(lián)呢?
對同一個符號引用進行多次解析請求是很常見的,比如你在代碼里面多次new同一個類。這里要分成兩種情況:
1) invokeddynamic指令:這個指令的特殊之處在于,它是為了支持動態(tài)語言而存在的,也就是說,必須等到程序?qū)嶋H運行這條指令的時候,解析動作才能進行[目前僅使用java語言并不會生成這條指令]。相對的,其余觸發(fā)的解析指定都是“靜態(tài)”的,可以在剛剛完成加載階段,還沒開始執(zhí)行代碼時就進行解析。
2) 除了上述的指令外,虛擬機實現(xiàn)可以對第一次解析的結(jié)果進行緩存(在運行時常量池中記錄直接引用,并把常量標識為已解析狀態(tài))。從而避免了多次解析。
解析動作主要針對“類或接口”,“字段”,“類方法”,“接口方法”,“方法類型”,“方法句柄”和“調(diào)用點限定符”7類符號引用進行[分別對應(yīng)7種常量池表的CONSTATN_Class_info,CONSTATN_Fieldref_info,CONSTATN_Methodref_info,CONSTATN_InterfaceMethodref_info,CONSTATN_MethodType_info,CONSTATN_MethodHandle_info,CONSTATN_InvokeDynamic_info,后續(xù)三種和動態(tài)類型有關(guān),目前java還是靜態(tài)類型語言]。

初始化

在虛擬機中嚴格規(guī)定需要對類進行初始化的,有下面五種情況:
1) 遇到new,getstatic,putstatic或者invokestatic這4條字節(jié)碼指令時。
2) 使用java.lang.reflect包的方法對類進行反射調(diào)用的時候。
3) 當初始化一個類,發(fā)現(xiàn)其父類并沒有初始化時,需要先初始化父類。
4) 虛擬機啟動時,用戶需要指定一個要執(zhí)行的主類(包含main()方法的類),虛擬機會先初始化這個類。
5) 當使用JDK1.7的動態(tài)語言支持時,如果一個java.lang.invoke.MethodHandle實例最后的解析結(jié)果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且這個方法句柄所對應(yīng)的類沒有初始化,則需要先觸發(fā)其初始化。
對于以上五種初始化場景,虛擬機規(guī)范中使用了“只有”,除此之外,所有的引用類的方式都不會觸發(fā)初始化。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/66901.html

相關(guān)文章

  • JVM 知識點 01

    摘要:新生代又被劃分為三個區(qū)域和兩個幸存區(qū)。這樣劃分的目的是為了使能夠更好地管理堆內(nèi)存中的對象,包括內(nèi)存的分配及回收。新生代主要存儲新創(chuàng)建的對象和尚未進入老年代的對象。 在Java中主要有以下三種類加載器: 引導類加載器(bootstrap class loader) --用來加載java的核心庫(Strin...

    不知名網(wǎng)友 評論0 收藏0
  • JVM實戰(zhàn)---類加載過程

    任何程序都需要加載到內(nèi)存才能與CPU進行交流 同理, 字節(jié)碼.class文件同樣需要加載到內(nèi)存中,才可以實例化類 ClassLoader的使命就是提前加載.class 類文件到內(nèi)存中 在加載類時,使用的是Parents Delegation Model(溯源委派加載模型) Java的類加載器是一個運行時核心基礎(chǔ)設(shè)施模塊,主要是在啟動之初進行類的加載、鏈接、初始化 showImg(https://s...

    bladefury 評論0 收藏0
  • jvm類加載機制

    摘要:前面提到,對于數(shù)組類來說,它并沒有對應(yīng)的字節(jié)流,而是由虛擬機直接生成的。對于其他的類來說,虛擬機則需要借助類加載器來完成查找字節(jié)流的過程。驗證階段的目的,在于確保被加載類能夠滿足虛擬機的約束條件。 Java 虛擬機將字節(jié)流轉(zhuǎn)化為 Java 類的過程。這個過程可分為加載、鏈接以及初始化 三大步驟。 加載是指查找字節(jié)流,并且據(jù)此創(chuàng)建類的過程。加載需要借助類加載器,在 Java 虛擬機中,類...

    lastSeries 評論0 收藏0
  • Java虛擬機如何加載類的?

    摘要:虛擬機有個一加載機制,叫做雙親委派模型。擴展類加載器擴展類加載器的父類的加載器是啟動類加載器。驗證驗證的目的就是需要符合虛擬機的規(guī)范。虛擬機會通過加鎖的方式確保方法只執(zhí)行一次。 引言 上一篇文章談到Java運行的流程,其中有一環(huán)是類加載。今天就繼續(xù)深入探討JVM如何加載虛擬機。首先JVM加載類的一般流程分三步:·加載·鏈接·初始化那么是否全部Java類都是這樣三步走的方式加載呢?我們可...

    TANKING 評論0 收藏0
  • 類的加載機制,雙親委派模型,搞定大廠高頻面試題

    摘要:驗證驗證是連接階段的第一步,這一階段的目的是為了確保文件的字節(jié)流中包含的信息符合當前虛擬機的要求,并且不會危害虛擬機自身的安全。字節(jié)碼驗證通過數(shù)據(jù)流和控制流分析,確定程序語義是合法的符合邏輯的。 看過這篇文章,大廠面試你「雙親委派模型」,硬氣的說一句,你怕啥? 讀該文章姿勢 打開手頭的 IDE,按照文章內(nèi)容及思路進行代碼跟蹤與思考 手頭沒有 IDE,先收藏,回頭看 (萬一哪次面試問...

    Object 評論0 收藏0
  • Java 虛擬機總結(jié)給面試的你(中)

    摘要:驗證過程驗證過程的目的是為了確保文件的字節(jié)流中包含的信息符合當前虛擬機的要求,并且不會危害虛擬機自身的安全。二虛擬機字節(jié)碼執(zhí)行引擎虛擬機的執(zhí)行引擎自行實現(xiàn),可以自行制定指令集與執(zhí)行引擎的結(jié)構(gòu)體系。 本篇博客主要針對Java虛擬機的類加載機制,虛擬機字節(jié)碼執(zhí)行引擎,早期編譯優(yōu)化進行總結(jié),其余部分總結(jié)請點擊Java虛擬總結(jié)上篇 。 一.虛擬機類加載機制 概述 虛擬機把描述類的數(shù)據(jù)從Clas...

    MRZYD 評論0 收藏0

發(fā)表評論

0條評論

ormsf

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<