<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      安卓筆記俠

      專注安卓開(kāi)發(fā)

      導(dǎo)航

      深入理解Java虛擬機(jī)04--類結(jié)構(gòu)文件

      一.程序存儲(chǔ)格式

      • 統(tǒng)一的程序存儲(chǔ)格式:不同平臺(tái)的虛擬機(jī)于所有平臺(tái)都統(tǒng)一使用程序存儲(chǔ)格式——字節(jié)碼(ByteCode);
      • Java 虛擬機(jī)不關(guān)心 Class 文件的來(lái)源,而只和“Class文件"這種二進(jìn)制文件格式關(guān)聯(lián),也就是說(shuō)Java虛擬機(jī)只認(rèn)識(shí)“Class"文件;
      • Java 編譯器可以把 Java 程序代碼編譯成虛擬機(jī)所需要的Class 文件;

      二.Class 文件結(jié)構(gòu)

      Class 文件是以 8 個(gè)字節(jié)為單位的二進(jìn)制流,緊湊排列,中間沒(méi)有空隙;如果想查看一個(gè) Class 文件除了通過(guò) winHex 編譯器看到字節(jié)碼,也可以通過(guò) javap -verbose xxx.Class 輸出字節(jié)碼內(nèi)容,這樣看起來(lái)比較直觀。
      1、基本類型
      無(wú)符號(hào)數(shù):

      • 定義:基本的數(shù)據(jù)類型,u1、u8表示1個(gè)字節(jié),8個(gè)字節(jié)。
      • 使用:可以用來(lái)描述數(shù)字、索引、引用,utf-8格式的字符串;

      表:

      • 定義:多個(gè)無(wú)符號(hào)數(shù)和其他表組成的復(fù)合數(shù)據(jù)類型;通常以“_info” 結(jié)尾。
      • 使用:描述有層次關(guān)系的復(fù)合結(jié)構(gòu)數(shù)據(jù);

      2、魔數(shù)與版本

      • 魔數(shù):每個(gè)Class文件的頭4個(gè)字節(jié),唯一作用就是確定這個(gè)文件是否能被一個(gè)虛擬機(jī)接受的Class文件;
      • 次版本號(hào):緊接著魔數(shù)后面的第5和第6個(gè)字節(jié);
      • 主版本號(hào):第7和第8個(gè)字節(jié)代表主版本號(hào),比如說(shuō)50對(duì)應(yīng)的就是JDK1.6.
      • 可以使用十六進(jìn)制編譯器WinHex打開(kāi)一個(gè)Class文件瞅瞅;

      3、常量池
        版本號(hào)之后緊跟的就是常量池入口,可以理解為Class文件之中的資源倉(cāng)庫(kù);

      • 常量池容量計(jì)數(shù)器:u2類型,代表本Class文件有N-1個(gè)常量(因?yàn)槭菑?開(kāi)始技術(shù)的);
      1. 0項(xiàng)常量:不引用任何一個(gè)常量池項(xiàng)目
      • 常量池放置的內(nèi)容每一項(xiàng)都是一個(gè)表,主要分兩類
      1. 字面量:文本字符串、final常量值等;
      2. 符號(hào)引用
        • 類和接口的全限定名
        • 字段的名稱和描述符
        • 方法的名稱和描述符
      • length:
      1. 定義:UTF-8編碼的字符串長(zhǎng)度是多少個(gè)字節(jié);
      2. 65535限制:Class文件中方法、字段等都需要引用CONSTANT_ Utf8_ info型常量的length為u2類型,最大為65535.如果某個(gè)變量或者方法名超過(guò)了64K,那么這個(gè)length容不下了,當(dāng)然也就無(wú)法編譯了。

      4、訪問(wèn)標(biāo)志(access_flags)

      • 常量池之后緊跟的就是訪問(wèn)標(biāo)志。主要包括了這個(gè)Class是類or接口,是不是 public,是不是 abstract 類型,是不是 final 類型。

      5、類索引、父類索引和接口類集合

      • java.lang.Object類索引為0;
      • 類的索引其實(shí)就是描述了這個(gè)Class的extends和implements的關(guān)系;

      6、字段表集合(field_info)

      • 用于描述定義的變量,依次包括了訪問(wèn)標(biāo)志(access_ flags)、名稱索引(name_ index)、描述索引(descriptor_ index)、屬性表集合(attributes)。
      • 描述的信息如下:
        1. 作用域:public、private、protect
        2. 實(shí)例or類變量:static
        3. 可變性:final
        4. 并發(fā)可見(jiàn)性:volatile
        5. 是否可序列化:transient
        6. 字段數(shù)據(jù)類型:基本類型、對(duì)象、數(shù)組等
        7. 字段名稱;
      • 字段表集合原則
        1. 1、不會(huì)列出超類or父類或者父接口繼承而來(lái)的字段;
        2. 2、有可能列出原本Java代碼中不存在的字段(內(nèi)部類會(huì)自動(dòng)添加指向外部類實(shí)例的字段,才能引用到外部類);
        3. 3、Java語(yǔ)言中字段是無(wú)法重載的;

      7、方法表集合
      和字段表集合差不多,方法表集合用來(lái)描述Class文件中的方法,但是訪問(wèn)標(biāo)志和屬性表集合和字段表集合有所區(qū)別;

      • 訪問(wèn)標(biāo)志:
        • volatile、transient關(guān)鍵字不可以修飾方法,方法表中少了這兩種標(biāo)志;
        • synchronized、native、strictfp和abstract可以修復(fù)方法,故方法表增加了這些對(duì)應(yīng)的標(biāo)志;
      • Code屬性:
        • 方法體中的代碼放在了“Code”屬性里面了;
      • 方法表集合原則
        • 方法沒(méi)有重寫(xiě)(Override),父類的信息不會(huì)寫(xiě)到子類的方法表中;
        • 編譯器有可能自動(dòng)添加一些方法,典型的如類構(gòu)造器的“< clinit >”、方法&實(shí)例構(gòu)造器的“< init >“方法;
        • 重載(Overload)一個(gè)方法,需要添加一個(gè)特征簽名,特征簽名就是一個(gè)方法中各個(gè)參數(shù)在常量池中的字段符號(hào)引用的集合;

      8、屬性表集合(attribute_info)
      上述那些表需要攜帶自己的某些屬性,來(lái)描述自己的特殊環(huán)境信息,比如InnderClasses、LineNumberTable、Code 之類的;

      • Code (用語(yǔ)描述代碼)
        • max_stack:操作棧深度最大值,JVM 運(yùn)行時(shí)根據(jù)這個(gè)值來(lái)分配棧幀(Stack Frame)中的操作棧深度;
        • max_locals:代表了局部變量表所需要的存儲(chǔ)空間。
          • Slot:虛擬機(jī)為局部變量分配內(nèi)存的最小單位
            • byte、char、float、int、short、boolean、returnAddress 長(zhǎng)度少于32位,占1個(gè)slot
            • double、long 64位,占2個(gè)slot
          • 當(dāng)代碼超出一個(gè)局部變量的作用域時(shí),這個(gè)局部變量所占用的 slot 可以被其他的局部變量所使用
        • code_length:字節(jié)碼長(zhǎng)度
        • code:存儲(chǔ)字節(jié)碼指令
        • 65535限制:虛擬機(jī)規(guī)定了一個(gè)方法不允許超過(guò) 65535 條字節(jié)碼,否則編譯不通過(guò);
        • 執(zhí)行:執(zhí)行過(guò)程中的數(shù)據(jù)交換、方法調(diào)用等操作都是基于棧(操作棧)的;
        • this關(guān)鍵字:在實(shí)例方法中通常可以有個(gè) this 關(guān)鍵字來(lái)引用當(dāng)前對(duì)象的變量,這是因?yàn)?Java 編譯時(shí)在局部變量表中自動(dòng)增加了這個(gè)(this)局部變量。
      • LineNumberTable:描述 Java 的源碼行號(hào)和字節(jié)碼行號(hào);
      • LocalVariableTable:描述局部變量表中的變量與Java源碼中定義的變量之間的關(guān)系;

       

      三.字節(jié)碼指令
      1、字節(jié)碼組成

      • 操作碼(Opcode):i(助記符)代表int類型數(shù)據(jù)操作....等等;
      • 操作數(shù) (Operands):永遠(yuǎn)都是一個(gè)數(shù)組類型的對(duì)象;

      Java虛擬機(jī)采用面向操作數(shù)棧而不是寄存器的架構(gòu),字節(jié)碼指令集是一種指令集架構(gòu)。放棄了操作數(shù)對(duì)齊,省略了填充的符號(hào)和間隔。
      2、加載和存儲(chǔ)指令
      將數(shù)據(jù)在幀棧中將局部變量表和操作數(shù)棧之間來(lái)回傳輸。

      • 將一個(gè)局部變量加載到操作棧;
      • 將一個(gè)數(shù)值從操作數(shù)棧存儲(chǔ)到局部變量表;
      • 將一個(gè)常量加載到操作數(shù)棧;
      • 擴(kuò)充局部變量表的訪問(wèn)索引的指令;

      3、運(yùn)算指令

      • 將兩個(gè)操作數(shù)棧上的值進(jìn)行某種特定運(yùn)算,并把結(jié)果重新存入到操作棧頂;
      • Java沒(méi)有直接支持byte、short、char、boolean類型,都轉(zhuǎn)為int類型進(jìn)行運(yùn)算,使用int的指令代替;

      4、類型轉(zhuǎn)換指令

      • 寬化轉(zhuǎn)換
        • int到long、float、double
        • long到float、double
        • float到double
      • 窄化轉(zhuǎn)換
        • 必須顯示的聲明轉(zhuǎn)換
        • 有溢出或者丟精的情況,但不會(huì)拋出異常

      5、同步指令

      • Java虛擬機(jī)支持方法級(jí)同步和方法內(nèi)部一段指令序列同步,這兩種同步都是通過(guò)“管程”來(lái)支持;
      • 執(zhí)行線程就要求先成功持有“管程”,然后才能執(zhí)行方法,最后方法執(zhí)行完成后,才釋放“管程”。
      • Java虛擬機(jī)通過(guò) monitorenter 和 monitorexit兩個(gè)指令配對(duì)使用,另外編譯器會(huì)自動(dòng)增加一個(gè)異常處理器。當(dāng)出現(xiàn)異常時(shí),這個(gè)異常處理器能夠捕獲到所有的異常,并且釋放“管程”,monitorexit 指令響應(yīng)。這樣的話,保證了 monitorenter 和monitorexit 總是成對(duì)出現(xiàn)的。

       三.代碼舉例

      1、Java文件:

       1 package com.xxx.ccc;
       2 public final class InitConfig {
       3     public static final InitConfig BFCACCOUNT = new InitConfig(0, "aaa", "AAA");
       4     private int mIndex;
       5     private String mData;
       6     private String mDescribe;
       7     private InitConfig(int indexFlag, String data, String describe) {
       8         this.mIndex = indexFlag;
       9         this.mData = data;
      10         this.mDescribe = describe;
      11     }
      12     public String getmData() {
      13         return this.mData;
      14     }

      2、Class 文件:

       1 Last modified 2017-7-4; size 1050 bytes
       2 MD5 checksum 2beb0c10f91b793c3570edcf2d1eff78
       3 Compiled from "InitConfig.java"
       4 public final class com.xxx.xxx.InitConfig
       5 minor version: 0  //次版本號(hào)
       6 major version: 51 //主版本號(hào)
       7 flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER  //訪問(wèn)標(biāo)志
       8 Constant pool: //常量池
       9  #1 = Methodref          #14.#41        // java/lang/Object."<init>":()V
      10  #2 = Fieldref           #5.#42         // com/xxx/xxx/InitConfig.mIndex:I
      11  #6 = Class              #46            // com/xxx/xxx/common/constant/ConstData
      12  #7 = String             #47            // aaa
      13  #23 = Utf8               <init>
      14  #24 = Utf8               (ILjava/lang/String;Ljava/lang/String;)V
      15  #25 = Utf8               Code
      16  #26 = Utf8               LineNumberTable  //Java的源碼行號(hào)和字節(jié)碼行號(hào)
      17  #27 = Utf8               LocalVariableTable //局部變量表中的變量與Java源碼中定義的變量之間的關(guān)系
      18  #28 = Utf8               this
      19  #32 = Utf8               getmData
      20  #33 = Utf8               ()Ljava/lang/String;
      21  #37 = Utf8               <clinit>
      22  #38 = Utf8               ()V
      23  #40 = Utf8               InitConfig.java
      24  #41 = NameAndType        #23:#38        // "<init>":()V
      25  #45 = Utf8               com/xxx/xxx/InitConfig
      26  #46 = Utf8               com/xxx/xxx/common/constant/ConstData
      27  #53 = NameAndType        #17:#16        // SEAACCOUNT:Lcom/xxx/ccc/InitConfig;
      28  #54 = Utf8               java/lang/Object
      29 public static final com.xxx.xxx BFCACCOUNT;
      30     descriptor: Lcom/xxx/xxx/InitConfig;
      31     flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL 
      32 public java.lang.String getmData();
      33     descriptor: ()Ljava/lang/String;
      34     flags: ACC_PUBLIC
      35     Code:
      36          stack=1, locals=1, args_size=1
      37             0: aload_0
      38             1: getfield      #3                  // Field mData:Ljava/lang/String;
      39          4: areturn
      40           LineNumberTable: //Java的源碼行號(hào)和字節(jié)碼行號(hào)
      41             line 36: 0
      42           LocalVariableTable: //局部變量表中的變量與Java源碼中定義的變量之間的關(guān)系
      43             Start  Length  Slot  Name   Signature
      44                0       5     0   this   Lcom/xxx/xxx/InitConfig;  //方法里面默認(rèn)增加了個(gè)this

      四.小結(jié)

        為什么說(shuō)一些”非Java"語(yǔ)言也是可以在 JVM 上跑,這是因?yàn)?JVM 只認(rèn)識(shí) Class 文件,所以如果某某語(yǔ)言最終編譯出的文件是 Class 文件,那么對(duì)于 JVM 來(lái)說(shuō)沒(méi)有什么區(qū)別,但是得按照 Class 文件的結(jié)構(gòu)來(lái),不然也無(wú)法正常執(zhí)行。Class 定義了許多特定的基本類型和表結(jié)構(gòu),通過(guò)魔數(shù)讓 JVM 認(rèn)識(shí)該文件,版本號(hào)保證可以在要求的 JDK 版本上運(yùn)行,在常量池中定義好常量,訪問(wèn)標(biāo)志位確定訪問(wèn)權(quán)限。索引集合方便與外界的 class 保持聯(lián)系,字段表保存我們定義好的變量,方法表存儲(chǔ)方法的信息,屬性表存儲(chǔ)了上述各種表的一些屬性。其中記住 slot為局部變量分配內(nèi)存的最小單位,當(dāng)程序超出作用域的時(shí)候,slot 可以被其他替換使用。到這里,僅僅是代碼最靜態(tài)的存儲(chǔ)的格式,程序要運(yùn)行起來(lái)。還需要操作指令,也是由字節(jié)碼存儲(chǔ),包括操作碼和操作數(shù)。有加載存儲(chǔ)、運(yùn)算、類型轉(zhuǎn)換、同步指令。

      posted on 2018-08-06 11:15  安卓筆記俠  閱讀(472)  評(píng)論(0)    收藏  舉報(bào)

      主站蜘蛛池模板: 成人午夜福利视频一区二区 | 亚洲一区精品视频在线| 狠狠做五月深爱婷婷天天综合 | 久久久综合香蕉尹人综合网| 亚洲v欧美v日韩v国产v| 色五开心五月五月深深爱| 玖玖在线精品免费视频| 17岁日本免费bd完整版观看| 99国产精品自在自在久久| 免费的特黄特色大片| 91青青草视频在线观看| 国产精品国产精品国产专区| 日本va欧美va精品发布| 亚洲国语自产一区第二页| 日本道播放一区二区三区| 久久精品夜夜夜夜夜久久| 国产台湾黄色av一区二区| 久久亚洲精品无码播放| 国产精品538一区二区在线| 日本人一区二区在线观看| 亚洲国产精品日韩在线| 日本黄页网站免费大全| 国产精品一区二区在线蜜芽tv| 国产成人免费高清激情视频| 城市| 中文字幕在线视频不卡一区二区 | 亚洲国产制服丝袜高清在线| 亚洲精品中文av在线| 亚洲人ⅴsaⅴ国产精品| 高清偷拍一区二区三区| 国产成人最新三级在线视频| 麻豆一区二区中文字幕| 中国亚州女人69内射少妇| AV老司机AV天堂| 99精品国产中文字幕| 色综合久久精品亚洲国产| 午夜精品国产自在| 亚洲国产成人久久77| 精品人妻av中文字幕乱| 狠狠色狠狠色综合| 蜜臀av色欲a片无人一区|