乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      java基礎(chǔ)知識(shí),JVM虛擬機(jī)類(lèi)加載機(jī)制

       internet_java 2020-02-29

      知識(shí)要點(diǎn):

      類(lèi)加載機(jī)制簡(jiǎn)介
      類(lèi)加載機(jī)制流程

      類(lèi)加載機(jī)制簡(jiǎn)介

      虛擬機(jī)把描述類(lèi)的數(shù)據(jù)從Class文件加載到內(nèi)存,并對(duì)數(shù)據(jù)進(jìn)行校驗(yàn)、轉(zhuǎn)換解析和初始化,最終形成可以被虛擬機(jī)直接使用的Java類(lèi)型,這就是虛擬機(jī)的類(lèi)加載機(jī)制。

      類(lèi)加載機(jī)制流程

      類(lèi)從被加載到虛擬機(jī)內(nèi)存中開(kāi)始,到卸載出內(nèi)存為止,它的整個(gè)生命周期包括:加載(Loading)、驗(yàn)證(Verification)、準(zhǔn)備(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸載(Unloading)7個(gè)階段。其中準(zhǔn)備、驗(yàn)證、解析3個(gè)部分統(tǒng)稱為連接(Linking)

      類(lèi)加載的過(guò)程包括了加載、驗(yàn)證、準(zhǔn)備、解析、初始化五個(gè)階段。在這五個(gè)階段中,加載、驗(yàn)證、準(zhǔn)備和初始化這四個(gè)階段發(fā)生的順序是確定的,而解析階段則不一定,它在某些情況下可以在初始化階段之后開(kāi)始,這是為了支持 Java 語(yǔ)言的運(yùn)行時(shí)綁定(也成為動(dòng)態(tài)綁定或晚期綁定)。另外注意這里的幾個(gè)階段是按順序開(kāi)始,而不是按順序進(jìn)行或完成,因?yàn)檫@些階段通常都是互相交叉地混合進(jìn)行的,通常在一個(gè)階段執(zhí)行的過(guò)程中調(diào)用或激活另一個(gè)階段。

      加載

      加載是類(lèi)加載過(guò)程的第一個(gè)階段,在加載階段,虛擬機(jī)需要完成以下三件事情:
      ①獲取二進(jìn)制字節(jié)流
      ②靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)
      ③在Java堆里面生成一個(gè)類(lèi)對(duì)象,作為方法區(qū)的訪問(wèn)入口。
      Java二進(jìn)制字節(jié)流可以獲取的途徑有:

      • 從ZIP包中讀取,JAR,WAR,EAR格式的基礎(chǔ)

      • 從網(wǎng)絡(luò)中獲取,Applet應(yīng)用

      • 運(yùn)行時(shí)計(jì)算生成,動(dòng)態(tài)代理技術(shù)

      • 由其他文件生成,JSP應(yīng)用,由JSP文件生成對(duì)應(yīng)的Class類(lèi)


      • 驗(yàn)證
      • 驗(yàn)證是連接階段的第一步,確保Class文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機(jī)的要求,并且不會(huì)危害虛擬機(jī)自身的安全。驗(yàn)證階段大致分下面4個(gè)動(dòng)作:


      • 文件格式驗(yàn)證

      • 元數(shù)據(jù)驗(yàn)證

      • 字節(jié)碼驗(yàn)證

      • 符號(hào)引用驗(yàn)證
        在驗(yàn)證過(guò)程中大致會(huì)拋出如下幾種錯(cuò)誤:

      • IncompatibleClassChangeError

      • Unsupported major.minor version

      • IllegalAccessError

      • NoSuchFieldError

      • NoSuchMethodError


      • 文件格式驗(yàn)證
      • 驗(yàn)證字節(jié)流是否符合Class文件格式的規(guī)范,并且能被當(dāng)前版本的虛擬機(jī)處理。

      • 驗(yàn)證Class文件的標(biāo)識(shí)。魔數(shù)是否以0xCAFEBABE開(kāi)頭

      • 驗(yàn)證Class文件的版本號(hào)。主次版本號(hào)是否在當(dāng)前虛擬機(jī)處理范圍之內(nèi)

      • 驗(yàn)證常量池。常量池的常量中是否有不被支持的常量類(lèi)型

      • 指向常量的各種索引值中是否有指向不存在的常量或不符合類(lèi)型的常量

      • CONSTANT_Utf8_info型的常量中是否有不符合UTF8編碼的數(shù)據(jù)

      • Class文件中各個(gè)部分及文件本身是否有被刪除的或附加的其他信息
        通過(guò)了這個(gè)階段的驗(yàn)證后,字節(jié)流才會(huì)進(jìn)入內(nèi)存的方法區(qū)中進(jìn)行存儲(chǔ)。后面的驗(yàn)證會(huì)基于方法區(qū)的存儲(chǔ)結(jié)構(gòu)進(jìn)行驗(yàn)證,而不再操作字節(jié)流進(jìn)行驗(yàn)證。


      • 元數(shù)據(jù)驗(yàn)證
      • 該階段主要對(duì)字節(jié)碼描述的信息進(jìn)行語(yǔ)義分析,以保證符合Java語(yǔ)言規(guī)范要求。

      • 類(lèi)是否有父類(lèi)(除了java.lang.Object外,所有類(lèi)都應(yīng)當(dāng)有父類(lèi))

      • 類(lèi)的父類(lèi)是否繼承了不允許被繼承的類(lèi)(final修飾的類(lèi))

      • 如果類(lèi)不是抽象類(lèi),是否實(shí)現(xiàn)了器父類(lèi)或接口中要求實(shí)現(xiàn)的所有方法

      • 類(lèi)中的字段,方法是否與父類(lèi)產(chǎn)生矛盾(如:覆蓋了父類(lèi)的final字段)

      • 字節(jié)碼驗(yàn)證
      • 該階段主要是通過(guò)數(shù)據(jù)流和控制流分析,確定程序語(yǔ)義是合法的。

      • 對(duì)類(lèi)的方法體進(jìn)行校驗(yàn)分析,保證被校驗(yàn)類(lèi)的方法在運(yùn)行時(shí)不會(huì)做出危害虛擬機(jī)安全的事件。

      • 符號(hào)引用驗(yàn)證
      • 符號(hào)引用驗(yàn)證是對(duì)類(lèi)自身以外(常量池中的各種符號(hào)引用)的信息進(jìn)行匹配性校驗(yàn),該階段在虛擬機(jī)將符號(hào)引用轉(zhuǎn)化為直接引用時(shí)發(fā)生。

      • 符號(hào)引用中通過(guò)字符串描述的全限定名是否能找到對(duì)應(yīng)的類(lèi)。

      • 在指定類(lèi)中是否存在符合方法的字段描述以及簡(jiǎn)單名稱所描述的方法和字段。

      • 符號(hào)引用中的類(lèi),字段,方法的訪問(wèn)性(private,protected,public,default)是否可被當(dāng)前類(lèi)訪問(wèn)。
        符號(hào)引用驗(yàn)證的目的就是確保解析動(dòng)作能正常執(zhí)行。

      • 準(zhǔn)備
      • 準(zhǔn)備階段是為類(lèi)變量分配內(nèi)存并設(shè)置類(lèi)變量初始化的階段,這些變量所使用的內(nèi)存當(dāng)將在方法區(qū)中進(jìn)行分
        配。只對(duì)類(lèi)變量進(jìn)行內(nèi)存分配(static修飾),不包括實(shí)例變量,實(shí)例變量將會(huì)在對(duì)象實(shí)例化是隨著對(duì)象一起分配在Java堆中。
        如:一個(gè)類(lèi)變量的定義為

        // n的初始化值是0,而不是2。因?yàn)檫@個(gè)時(shí)候還沒(méi)執(zhí)行任何初始化方法(<clinit>)。 public static int n = 2;

        再例如:

        // 編譯時(shí)會(huì)為m生成ConstantValue屬性,在準(zhǔn)備階段會(huì)根據(jù)ConstantValue將m值設(shè)置為2 public static final int m = 2;



      • 類(lèi)變量和實(shí)例變量

      • 類(lèi)變量:也稱為靜態(tài)變量,在類(lèi)中以static關(guān)鍵字聲明,但必須在方法構(gòu)造方法和語(yǔ)句塊之外

      • 實(shí)例變量:屬于該類(lèi)的對(duì)象,必須產(chǎn)生該類(lèi)對(duì)象,才能調(diào)用實(shí)例變量。
        解析
        解析的目的就是將常量池內(nèi)的符號(hào)引用替換為直接引用。

      • 符號(hào)引用(Symbolic References):符號(hào)引用以一組符號(hào)來(lái)描述所引用的目標(biāo),符號(hào)可以是任何形式的字面量,只要使用時(shí)能無(wú)歧義地定位到目標(biāo)即可。符號(hào)引用與虛擬機(jī)實(shí)現(xiàn)的內(nèi)存布局無(wú)關(guān),引用的目標(biāo)并不一定已經(jīng)加載到內(nèi)存中。符號(hào)引用的字面量形式已經(jīng)明確定義在Java虛擬機(jī)規(guī)范的Class文件格式中。

      • 直接引用(Direct References):直接引用可以是直接指向目標(biāo)的指針,相對(duì)偏移量或是一個(gè)能間接定位到目標(biāo)的句柄。直接引用與虛擬機(jī)實(shí)現(xiàn)的內(nèi)存布局相關(guān),同一個(gè)符號(hào)引用在不用虛擬機(jī)實(shí)例上翻譯出來(lái)的直接引用一般不同。如果有了直接引用,那引用的目標(biāo)必定已經(jīng)在內(nèi)存中存在。
        一句話總結(jié):符號(hào)引用是以字面量的形式明確定義在常量池中;直接引用是指向目標(biāo)的指針,或者相對(duì)偏移量。
        解析動(dòng)作主要對(duì)類(lèi)或者接口、字段、類(lèi)方法、接口方法、方法類(lèi)型、方法句柄和調(diào)用點(diǎn)限定符7類(lèi)符號(hào)引用進(jìn)行,分別對(duì)應(yīng)于常量池

      • CONSTANT_Class_info

      • CONSTANT_Fieldref_info

      • CONSTANT_Methodref_info

      • CONSTANT_InterfaceMethodref_info

      • CONSTANT_MethodType_info

      • CONSTANT_Methodref_info

      • CONSTANT_MethodHandler_info

      • CONSTANT_invokeDynamic_info
        字段的解析

        class A extends B implements C, D{ 

        private String str; //字段的解析

        }

        解析字段的順序:
        ①先查找本類(lèi)A,如果包含了簡(jiǎn)單名稱和字段描述符都與目標(biāo)相匹配的字段,則返回這個(gè)字段的直接引用,查找結(jié)束。
        ②否則,在接口中查找。將會(huì)按照集成關(guān)系從下往上遞歸搜搜各個(gè)接口和它的父接口,如果接口中包含了簡(jiǎn)單名稱和字段描述符都于目標(biāo)相匹配的字段,則返回這個(gè)字段的直接引用,查找結(jié)束。
        ③否則,在父類(lèi)中查找,如果在父類(lèi)中包含了簡(jiǎn)單名稱和字段描述符都于目標(biāo)相匹配的字段,則返回這個(gè)字段的直接引用,查找結(jié)束
        ④否則,查找失敗,拋出java.lang.NoSuchFieldError異常。
        類(lèi)方法的解析

        class A extends B implements C, D{ 

        private void inc(); //方法的解析

        }

        ①如果在類(lèi)方法表中發(fā)現(xiàn)class_index中索引的A是一個(gè)接口,哪就直接拋出java.lang.IncompatiableClassChangeError異常。
        ②如果通過(guò)了第一步,先查找本類(lèi)A,是否由簡(jiǎn)單名稱和描述符都于目標(biāo)相匹配的方法,如果有則返回方法的直接引用,查找結(jié)束。
        ③否則,父親中遞歸查找是否又簡(jiǎn)單名稱和描述符都與目標(biāo)相匹配的方法,如果有則返回這個(gè)方法的直接引用,查找結(jié)束。
        ④否則,在類(lèi)實(shí)現(xiàn)的接口列表及它們的父接口之中查找是否有簡(jiǎn)單名名稱和描述符都與目標(biāo)相匹配的方法,如果存在匹配的方法,說(shuō)明類(lèi)C是一個(gè)抽象類(lèi),這時(shí)查找結(jié)束,拋出java.lang.AbastractMethodError異常。
        ⑤否則,宣告方法查找失敗,拋出java.lang.NoSuchMethodError。

        接口方法的解析
        與類(lèi)的方法解析不同,如果在接口方法表中發(fā)現(xiàn)class_index中的索引A是個(gè)類(lèi)而不是接口,那就直接拋出java.lang.IncompatiableClassError異常。
        否則,先查找本接口,是否有簡(jiǎn)單名稱和描述符都與目標(biāo)匹配的方法,如果有則返回這個(gè)方法的直接引用,查找結(jié)束。
        否則,在接口的父接口中遞歸查找,直到j(luò)ava.lang.Object類(lèi)(查找范圍包括Object類(lèi))為止,看是否有簡(jiǎn)單名稱和描述符都與目標(biāo)相匹配的方法,如果有則返回這個(gè)方法的直接引用,查找結(jié)束。
        否則,宣告方法查找失敗,拋出java.lang.NoSuchMethodError異常。

        初始化
      • <clinit> 類(lèi)的初始化。靜態(tài)變量,靜態(tài)塊的初始化。所有的類(lèi)變量初始化語(yǔ)句和類(lèi)型的靜態(tài)初始化器。
        Java在編譯之后會(huì)在字節(jié)碼文件中生成<clinit>方法,稱之為類(lèi)構(gòu)造器,類(lèi)構(gòu)造器同實(shí)例構(gòu)造器一樣,也會(huì)對(duì)靜態(tài)語(yǔ)句塊,靜態(tài)變量進(jìn)行初始化
        <init> 對(duì)象的初始化
        Java在編譯之后會(huì)在字節(jié)碼文件中生成<init>方法,稱之為實(shí)例構(gòu)造器。該實(shí)例構(gòu)造器會(huì)對(duì)語(yǔ)句塊,變量進(jìn)行初始化,并調(diào)用父類(lèi)的構(gòu)造器。
        <clinit>方法是在類(lèi)加載過(guò)程中執(zhí)行的,而<init>是在對(duì)象實(shí)例化執(zhí)行的,所以<clinit>一定比<init>先執(zhí)行。所以整個(gè)順序就是:

      • 父類(lèi)靜態(tài)變量初始化

      • 父類(lèi)靜態(tài)語(yǔ)句塊

      • 子類(lèi)靜態(tài)變量初始化

      • 子類(lèi)靜態(tài)語(yǔ)句塊

      • 父類(lèi)變量初始化

      • 父類(lèi)語(yǔ)句塊

      • 父類(lèi)構(gòu)造函數(shù)

      • 子類(lèi)變量初始化

      • 子類(lèi)語(yǔ)句塊

      • 子類(lèi)構(gòu)造函數(shù)

        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類(lèi)似文章 更多