深入理解 JVM 類文件結(jié)構(gòu)

1.流程

  • 創(chuàng)建 HelloWorld.java
    代碼如下
    package jvm;

      /**
       * @author lidiqing
       * @since 2017/3/4.
       */
      public class HelloWorld {
      
          private final String text = "Hello World!";
      
          public HelloWorld() {
          }
      
          public String getText() {
              return text;
          }
      }
    
  • 編譯成 HelloWorld.class

  • 使用 javap -verbose HelloWorld.class輸出字節(jié)信息

    javap輸出

  • 使用 winhex 查看二進制數(shù)據(jù)
    winhex輸出

2.結(jié)構(gòu)詳解

2.1 Class 文件格式

2.1.1 概述

結(jié)構(gòu):Class 文件 == 8位字節(jié)為單位的二進制流 == 無符號數(shù) + 表

  • u2, u4 => 無符號數(shù)利术,代表2個字節(jié),u4 代表4個字節(jié)
  • xxx_info => 表捐康,無符號數(shù)或其他表構(gòu)成椅棺,整個 class 就是一張表
    • cp_info 常量表
    • field_info 字段表
    • method_info 方法表
    • attribute_info 屬性表

特點:

  • 不依賴于任何操作系統(tǒng)
  • 數(shù)據(jù)存儲使用大端字節(jié)序

文件格式:

類型 名稱 數(shù)量
u4 magic 1
u2 minor_version 1
u2 major_version 1
u2 constant_pool_count 1
cp_info constant_pool constant_pool-1
u2 access_flags 1
u2 this_class 1
u2 super_class 1
u2 interfaces_count 1
u2 interfaces interfaces_count
u2 fields_count 1
field_info fields fields_count
u2 methods_count 1
method_info methods methods_count
u2 attributes_count 1
attribute_info attributes attributes_count

2.2 魔數(shù)和版本

2.2.1 概述

  • 魔數(shù)
    唯一作用:確認該文件能被虛擬機接受
    類加載過程中的驗證階段曹步,會判斷該 Magic

  • 版本號和編譯器 JDK 有關(guān)

2.2.2 數(shù)據(jù)分析

魔術(shù)和版本對應數(shù)據(jù)
  • magic
    固定值:0xCAFEBABY

  • minor_version
    次版本號:0x0000

  • major_version
    主版本號:0x0034

2.2.3 表

Class 文件的版本表

編譯器版本 -target參數(shù) 十六進制版本號 十進制版本號(主版本號.次版本號)
JDK 1.7.0 不帶(默認 -target 1.7) 00 00 00 33 51.0
JDK 1.7.0 -target 1.6 00 00 00 32 50.0
JDK 1.8.0 不帶(默認 -target 1.8) 00 00 00 34 52.0

2.3 常量池(常量表集合)

2.3.1 概述

特點:

  • Class 文件的資源倉庫
  • Class 文件中和其他項目關(guān)聯(lián)最多
  • Class 文件中最大的數(shù)據(jù)項目之一

主要類型:

  • 字面量梯码,語言層面的常量宁玫,如文本字符串固惯,final常量(如字符串 'HelloWorld!')
  • 符號引用亲桥,編譯層面的常量
    • 類和接口的全限定名(如 jvm/HelloWorld
    • 字段的名稱和描述符 (如 jvm/Helloworld/text:Ljava/lang/String;)
    • 方法的名稱和描述符(如 java/lang/Object."<init>":()V

作用:

無論是字段表穴张、方法表還是屬性表,只要涉及到一些常量或者描述两曼,都會有個索引指向該表的某個位置

2.3.2 數(shù)據(jù)分析

在 class 中的二進制數(shù)據(jù)

常量池的二進制數(shù)據(jù)
  • constant_pool_count => 0x19
    容量計數(shù)皂甘,常量表從 1 開始計數(shù),所以 0x19 只有 0x18 個常量悼凑,十進制 24 個常量
    這樣的話偿枕,如果因為其他地方用了索引為 0,常量為空户辫,比如 java.lang.Object 對象是所有類的基類渐夸,父索引為 0

  • constant_pool
    對照 2.3.3 的常量池結(jié)果總表來進行分析,直接用 javap 輸出 24 個常量如下

      Constant pool:
         #1 = Methodref          #5.#20         // java/lang/Object."<init>":()V
         #2 = String             #21            // Hello World!
         #3 = Fieldref           #4.#22         // jvm/HelloWorld.text:Ljava/lang/String;
         #4 = Class              #23            // jvm/HelloWorld
         #5 = Class              #24            // java/lang/Object
         #6 = Utf8               text
         #7 = Utf8               Ljava/lang/String;
         #8 = Utf8               ConstantValue
         #9 = Utf8               <init>
        #10 = Utf8               ()V
        #11 = Utf8               Code
        #12 = Utf8               LineNumberTable
        #13 = Utf8               LocalVariableTable
        #14 = Utf8               this
        #15 = Utf8               Ljvm/HelloWorld;
        #16 = Utf8               getText
        #17 = Utf8               ()Ljava/lang/String;
        #18 = Utf8               SourceFile
        #19 = Utf8               HelloWorld.java
        #20 = NameAndType        #9:#10         // "<init>":()V
        #21 = Utf8               Hello World!
        #22 = NameAndType        #6:#7          // text:Ljava/lang/String;
        #23 = Utf8               jvm/HelloWorld
        #24 = Utf8               java/lang/Object    
    

Methodref渔欢,是方法的符號引用墓塌,比如虛擬機調(diào)用 invokespecial 指令會用到,比如該類的初始化方法字節(jié)碼指令中有這么一條

    1: invokespecial #1

這樣會實例化 #1 的方法,而 #1 是 java.lang.Object 的初始化方法苫幢,所以該指令執(zhí)行了 Object 的初始化
Fieldref访诱,是字段的符號引用,比如虛擬機調(diào)用 putfield 指令會去解析該符號引用

    7: putfield #3    

這樣的話會把該符號引用對應的變量韩肝,設置為棧幀中的值
NameAndType触菜,字段或者方法的描述,有名稱和描述符組合起來
Class哀峻,表示一個類的全限定名
String涡相,表示一個字符串常量
Utf8,使用 utf-8 格式編碼的字符串剩蟀,最后其他類型的常量都會指向這些值催蝗,這是最基本的常量值

Class 文件加載后,常量池的字面量和符號引用會被存入方法區(qū)育特,多個線程共享丙号。方法區(qū)又稱為永久帶,GC 基本不在方法區(qū)進行垃圾回收且预。但也會有槽袄,比如一些廢棄的常量和無用的類

2.4 訪問標志

2.4.1 概述

識別類或接口層次的訪問信息

u2類型=2個字節(jié)=16位可用烙无,目前只定義了8個锋谐,可見后面的訪問標志表

2.4.2 數(shù)據(jù)分析

在 class 中的二進制信息

訪問標志二進制數(shù)據(jù)
  • access_flags

該值為 0x21 = 0x01| 0x20

0x01 => ACC_PUBLIC
0x20 => ACC_SUPER

對照訪問標志表,可知是一個普通的 public 類
使用 JDK 1.0.2 之后編譯出來的類的 ACC_SUPER 均為真

2.4.3 訪問標志表

標志名稱 標志值 含義
ACC_PUBLIC 0x0001 是否public類型
ACC_FINAL 0x0010 是否final類型截酷,只有類可用
ACC_SUPER 0x0020 JDK1.2 之后必須為真
ACC_INTERFACE 0x0200 標記是接口
ACC_ABSTRACT 0x400 是否abstract類型涮拗,接口或抽象類為真,其他類為假
ACC_SYNTHETIC 0x1000 標記類不是用戶代碼產(chǎn)生
ACC_ANNOTATION 0x2000 標記是注解
ACC_ENUM 0x4000 標記是枚舉

2.5 索引集合

2.5.1 概述

分為三種類型用來確定整個類的繼承關(guān)系迂苛,屬于類的元數(shù)據(jù)

  • 類索引(this_class)
  • 父類索引(super_class)
  • 接口索引集合(interfaces)

根據(jù)規(guī)則三热,每個類只能有一個父類,但可以有多個接口
而更特殊的 java.lang.Object 是沒有父類的三幻,畢竟是所有類的基類就漾,所以有且僅有 Object 類的父類索引為 0

2.5.2 數(shù)據(jù)分析

在 class 中的二進制信息

索引集合二進制數(shù)據(jù)
  • this_class => 0x0004
    這里指向常量池第4個常量,為 Class念搬,全限定名為 jvm/HelloWorld
    使用 javap 解析到的數(shù)據(jù)

      Constant pool
          #4 = Class      #23
          #23 = Utf8      jvm/HelloWorld
    

這個索引用來表示該類的全限定名

  • super_class => 0x0005
    常量池第5個常量抑堡,為 Class,全限定名為 java/lang/Object
    使用 javap 解析到的數(shù)據(jù)

      Constant pool
          #5 = Class      #24
          #24 = Utf8      java/lang/Object    
    

這個索引用來表示該類父類的全限定名朗徊,所以該類的父類就是 java/lang/Object

  • interfaces_count => 0x0000
    接口數(shù)量為 0
    因為沒有實現(xiàn)任何接口

  • interfaces
    因為接口數(shù)量為 0首妖,所以后面沒有接口數(shù)據(jù)

2.6 字段表集合

2.6.1 概述

范圍:包含類級、實例級變量爷恳,不包括方法內(nèi)部聲明的局部變量

信息:

使用標記表示

  • 作用域
    • public
    • private
    • protect
  • static 實例變量還是類變量
  • final 可變性
  • volatile 并發(fā)可見性
  • transient 可被序列化

用常量表示

  • 字段數(shù)據(jù)類型(基本類型有缆、對象、數(shù)組)
  • 字段名稱

2.6.2 數(shù)據(jù)分析

字段表集合二進制數(shù)據(jù)
  • fields_count => 0x0001
    有一個字段

  • fields
    從 fields_count 知道只有一個字段,查表可以得到 field_info 各個部分為:
    access_flags => 0x0012=0x0010|0x0002
    根據(jù)字段訪問標志可知棚壁,這是個 private 和 final 型屬性
    name_index => 0x0006
    索引對應常量池第6個常量杯矩,名為 “text”

      Constant pool
          #6 = Utf8       text    
    

descriptor_index => 0x0007
索引對應常量池第7個常量,所以描述符為 “Ljava/lang/String;”

    Constant pool
        #6 = Utf8       Ljava/lang/String;  

attribute_count => 0x0001
所以該字段有一個屬性灌曙,接下來就是詳細的 attribute_info 數(shù)據(jù)菊碟,表示該字段的屬性
attribute_name_index => 0x0008
索引對應常量池第8個常量,屬性名稱為 “constantvalue”

    Constant pool
        #8 = Utf8       constantvalue    

該屬性用來通知虛擬機自動為靜態(tài)變量賦值在刺。這個發(fā)生在類的加載過程中的初始化階段逆害。關(guān)于類變量,初始化的時候會給默認值蚣驼,但如果有 Constantvalue 屬性魄幕,就會用這個屬性的值來對類變量進行初始化
attribute_length => 0x00000002
constantvalue 的該值固定為 2,因為后面需要 u2 類型的數(shù)據(jù)來指向常量池颖杏,表示該 constantvalue 的值
constantvalue_index => 0x0002纯陨,索引對應常量池第2個常量,值為 “Hello World留储!”

    Constant pool
        #2 = String     #21
        #21 = Utf8      Hello World!    

實際上翼抠,用代碼進行比較的話,上面字段對應 Java 源碼為

    private final String text = "Hello World!";    

在編譯成 class 文件后获讳,我們可以解析到這樣的結(jié)果

    flags: ACC_PRIVATE ACC_FINAL
    name: text
    descriptor: Ljava/lang/String;
    attributes:
        constantvalue:HelloWorld!

在 Java 中用 static 和 final 修飾的字段阴颖,即該類的常量字段。在 Java 編譯階段的常量傳播優(yōu)化中丐膝,如果 B 只引用了 A 的常量量愧,編譯后 A 的常量會被轉(zhuǎn)化為 B 的常量,存入 B 類的常量池里帅矗。所以偎肃,常量傳播優(yōu)化后,使用者 B 就會擁有 A 的常量浑此,對 A 常量的引用在 Class 文件中成為對自己的常量的引用

2.6.3 表

字段表(field_info):

類型 名稱 數(shù)量
u2 access_flag 1
u2 name_index 1
u2 descriptor_index 1
u2 attributes_count 1
attribute_info attributes attributes_count

字段訪問標志(access_flag):

標志名稱 標志值 含義
ACC_PUBLIC 0x0001 是否 public
ACC_PRIVATE 0x0002 是否 private
ACC_PROTECTED 0x0004 是否 protected
ACC_STATIC 0x0008 是否 static
ACC_FINAL 0x0010 是否 final
ACC_VOLATILE 0x0040 是否 volatile
ACC_TRANSIENT 0x0080 是否 transient
ACC_SYNTHETIC 0x1000 是否 synthetic
ACC_ENUM 0x4000 是否 enum

描述符(descriptor):

標識字符 含義
B 基本類型 byte
C 基本類型 char
D 基本類型 double
F 基本類型 float
I 基本類型 int
J 基本類型 long
S 基本類型 short
Z 基本類型 boolean
V 特殊類型 void
L 對象類型累颂,如 Ljava/lang/Object

數(shù)組每一維度用 “[” 來描述

比如

  • int[] => [I
  • string[][] => [[java/lang/String;
  • void inc => ()V
  • String toString => ()Ljava/lang/String;
  • int indexof(char[] a, int b, char[] c, int d) => ([CI[CI)I

類的字段和方法都由兩部分來表示,即名稱和描述符(NameAndType)

2.7 方法表集合

2.7.1 概述

特點:

  • 方法中的代碼凛俱,被編譯成字節(jié)碼后紊馏,放在了 “Code” 屬性中
  • 如果父類的方法沒有被子類重寫,不會出現(xiàn)父類方法的信息
  • 會出現(xiàn)編譯器添加的方法最冰,比如類構(gòu)造器“<clinit>”和實例構(gòu)造器“<init>
  • Java 文件中同一個類中的方法的特征簽名不能一致瘦棋;Class 文件特征簽名可以一致,但返回值要不同

特征簽名 => 一個方法中各個參數(shù)在常量池中的字段符號的引用集合暖哨,不包含返回值

2.7.2 數(shù)據(jù)分析

方法表集合二進制數(shù)據(jù)
  • methods_count => 0x0002
    表示該類有兩個方法

  • methods
    分別有兩個方法赌朋,都是 method_info 的結(jié)構(gòu)凰狞。methods_count 緊接著就是第一個方法表
    現(xiàn)在只分析第一個方法表
    access_flag => 0x0001
    方法為 Public 方法
    name_index => 0x0009
    方法名稱為常量表第9個常量,是 Utf8 類型沛慢,為 “<init>”赡若,所以這個方法是類的初始化方法

      Constant pool
          #9 = Utf8       <init>  
    

descriptor_index => 0x000A
方法描述符為常量表第10個常量,也是 Utf8 類型团甲,為 “()V”

    Constant pool
        #10 = Utf8      ()V    

attribute_count => 0x0001
屬性數(shù)量為 1逾冬。從這個可知,該方法有一個屬性躺苦。
基本上所有方法都至少有一個屬性 “Code” 用來記錄方法中編譯后的字節(jié)碼指令身腻。也可以說,方法中的代碼編譯成字節(jié)碼指令后都被存入了 “Code” 屬性中了
attribute_name_index => 0x000B
常量表第11個常量匹厘,也是 Utf8 類型嘀趟,就是 “Code” 屬性

    Constant pool
        #11 = Utf8      Code    

attribute_length => 0x0000003D
表示接下來的 61 個字節(jié)就是 “Code” 屬性表的內(nèi)容了,關(guān)于這個屬性表的解析在后面
使用 javap 可以得出詳細的解析結(jié)果如下:

javap的解析結(jié)果

2.7.3 表

方法表(method_info):

類型 名稱 數(shù)量
u2 access_flags 1
u2 name_index 1
u2 descriptor_index 1
u2 attributes_count 1
attribute_info attributes attributes_count

方法訪問標志(access_flag):

標志名稱 標志值 含義
ACC_PUBLIC 0x0001 是否為 public
ACC_PRIVATE 0x0002 是否為 private
ACC_PROTECTED 0x0004 是否為 protect
ACC_STATIC 0x0008 是否為 static
ACC_FINAL 0x0010 是否為 final
ACC_SYNCHRONIZED 0x0020 是否為 synchronized
ACC_BRIDGE 0x0040 是否為編譯器產(chǎn)生的橋接方法
ACC_VARARGS 0x0080 是否接受不定參數(shù)
ACC_NATIVE 0x0100 是否為 native
ACC_ABSTRACT 0x0400 是否為 abstract
ACC_STRICTFP 0x0800 是否為 strictfp
ACC_SYNTHETIC 0x1000 是否為編譯器自動產(chǎn)生的

2.8 屬性表集合

2.8.1 概述

上面已經(jīng)有用到兩種屬性愈诚,字段用到 constantvalue 用來表示是一個常量她按,方法用到了 code 來記錄方法的字節(jié)碼指令集合

特點:

  • 屬性不要求嚴格按順序排列,只要不重名
  • 屬性值的結(jié)構(gòu)可完全自定義炕柔,但虛擬機只取自己認識的

2.8.2 基本結(jié)構(gòu)

類型 名稱 數(shù)量
u2 attribute_name_index 1
u4 attribute_length 1
u1 info attribute_length

每個屬性的名稱都要從常量池中拿一個 Utf8 類型的常量酌泰。屬性的內(nèi)容為 attribute_length 個 info 組成,每個 info 由一個字節(jié)組成匕累。所以屬性的組成是很靈活的陵刹,如何解釋這些 info,有虛擬機的標準哩罪,也可以完全自定義授霸。但虛擬機在解析的時候巡验,只取自己標準的那部分

2.8.3 幾個主要屬性

2.8.3.1 Code 屬性

使用在方法表中际插,用來表示代碼編譯成的字節(jié)碼指令

具體的結(jié)構(gòu)為

類型 名稱 數(shù)量
u2 attibute_name_index 1
u4 attribute_length 1
u2 max_stack 1
u2 max_locals 1
u4 code_length 1
u1 code code_length
u2 exception_table_length 1
exception_info exception_table exception_length
u2 attributes_count 1
attribute_info attributes attributes_count

現(xiàn)在拿類第一個方法表的 Code 屬性來進行分析

第一個方法表的 code 屬性二進制數(shù)據(jù)

  • attribute_name_indexattribute_length 上面已經(jīng)解析過了,為 “Code”显设,長度為 29框弛。即后面的 29 個字節(jié)均為該屬性的內(nèi)容

  • max_stack => 0x0002
    操作數(shù)棧的最大深度,方法執(zhí)行的任意時刻捕捂,操作數(shù)棧不會超過這個深度瑟枫,虛擬機用這個值來分配棧幀(Stack Frame)中的操作數(shù)棧深度。這里表示該方法的操作數(shù)棧最深為 2指攒。如果虛擬機執(zhí)行的時候慷妙,有出現(xiàn)超出了這個深度,會拋出 Stack Overflow 的異常

  • max_locals => 0x0001
    局部變量表所需的存儲空間允悦。該值的單位為 Slot膝擂,長度不超過 32 位的數(shù)據(jù)類型,比如 byte,int 等用一個 Slot架馋,而 double 和 long 用兩個 Slot狞山。這里表示方法局部變量的存儲空間為 1 個Slot

  • code_length => 0x0000000B
    方法體內(nèi)的字節(jié)碼長度,這里的長度為 11叉寂,所以接下來 11 位就是字節(jié)碼指令了

  • code
    方法體的字節(jié)碼指令萍启,每個指令用一個 u1 表示,即 8 位屏鳍,一共可以表達 256 條指令勘纯,目前虛擬機已經(jīng)定義 200 多條了。code 指令可以分成以下幾種類型钓瞭。其中異常指令只記錄顯示拋出(throw)的異常屡律,而像 try...catch 的異常則有屬性表之異常表來處理

    • 加載和存儲
    • 運算
    • 類型轉(zhuǎn)換
    • 對象的創(chuàng)建和訪問
    • 操作數(shù)棧管理
    • 控制轉(zhuǎn)移
    • 方法調(diào)用和返回
    • 異常
    • 同步指令
  • attributes_count => 0x00000002
    表示后面還有兩個屬性,對照表可知為 LineNumberTable 和 LocalVariableTable降淮。這兩個屬性都不是必須的超埋,主要用來描述源碼和字節(jié)碼之間的一些關(guān)系

因為該方法比較簡單,沒有異常等佳鳖。如果有異常霍殴,Code 屬性中還會有異常表 Exception table

2.8.3.2 LineNumberTable 屬性

用處

  • 描述 Java 源碼和字節(jié)碼行號的對應關(guān)系
  • 可以使用 javac -g:none 或 -g:lines 選項來取消或顯示。默認顯示
  • 用來實現(xiàn)斷點調(diào)試(如果沒有的話無法斷點)

LineNumberTable 具體的結(jié)構(gòu)為

類型 名稱 數(shù)量
u2 attribute_name_index 1
u4 attribute_length 1
u2 line_number_table_length 1
line_number_info line_number_table line_number_table_length

line_number_info 由 start_pc 和 line_number 組成系吩,分別表示字節(jié)碼行號和源碼行號

現(xiàn)在拿上面的方法的 LineNumberTable 屬性數(shù)據(jù)來進行分析

第一個方法的 Code 屬性的 LineNumberTable 的二進制數(shù)據(jù)
  • attribute_name_index => 0x000C
    屬性名稱来庭,指向常量池第 12 個常量,可以得知就是 “LineNumberTable”

      Constant pool
          #12 = Utf8      LineNumberTable 
    
  • attribute_length => 0x0000000E
    屬性的長度為 15穿挨,所以接下來 15 個字節(jié)都是 LineNumberTable 屬性的值

  • line_number_table_length => 0x0003
    表示接下來有 3 個的 line_number_info 類型月弛,用來表示字節(jié)碼和源碼的對應關(guān)系。有可能多個字節(jié)指令才會對應一條源碼

  • line_number_table
    現(xiàn)在就分析第一個 line_number_info 的信息
    start_pc => 0x0000科盛,字節(jié)碼第0行
    PC 的全稱為 Program Counter帽衙,即程序計數(shù),對應程序計數(shù)器的值贞绵,表示在字節(jié)碼指令中的偏移量厉萝。因為要保證線程切換后能回到正確的位置,所以每個線程都會有一個程序計數(shù)器
    line_number => 0x000B榨崩,源碼第11行
    結(jié)合 start_pc 可知谴垫,所以 0:aload_0 指令對應的源碼為 public HelloWorld() {

使用 javap 解析到方法 “<init>” 的完整 LineNumberTable 表如下

javap解析到的結(jié)果

有了這些class文件中有了這些信息,我們就可以進行斷點調(diào)試了母蛛。所以斷點調(diào)試是依賴于方法表中是否有設置 LineNumberTable 屬性

2.8.3.3 LocalVariableTable 屬性

用處

  • 描述棧幀局部變量表中的變量和 Java 源碼中對應的變量之間的關(guān)系
  • 可使用 -g:none 或 -g:vars 來取消或者生產(chǎn)這項信息
  • 沒有該屬性翩剪,當其他人引用這個方法,所有的參數(shù)名稱丟失彩郊,IDE 會使用 arg0前弯、arg1 等占位符代替

LocalVariableTable 具體的結(jié)構(gòu)為

類型 名稱 數(shù)量
u2 attribute_name_index 1
u4 attribute_length 1
u2 local_variable_table_length 1
local_variable_info local_variable_table local_variable_table_length

local_variable_info 的結(jié)構(gòu)為

類型 名稱 數(shù)量
u2 start_pc 1
u2 length 1
u2 name_index 1
u2 descriptor_index 1
u2 index 1

用第一個方法表的 code 屬性的 LocalVariableTable 屬性數(shù)據(jù)來分析

第一個方法表的 code 屬性的 LocalVariableTable 屬性的二進制數(shù)據(jù)
  • attribute_name_index => 0x000D
    指向常量池第 13 個常量舞肆,可以得知就是 “LocalVariableTable”

  • attribute_length => 0x0000000C
    屬性的長度為 12,所以接下來 12 個字節(jié)都是 LocalVariableTable 屬性的值

  • local_variable_table_length => 0x0001
    表示接下來有一個 local_variable_info 用來表示棧幀內(nèi)局部變量表和源碼的關(guān)系

  • local_varibale_info
    start_pc => 0x0000
    該局部變量的生命周期開始的字節(jié)碼偏移量
    length => 0x000B
    該局部變量的生命周期作用范圍的長度
    所以該局部變量作用在 0 -> 11 條字節(jié)碼之間博杖,可知為整個方法的字節(jié)碼指令集范圍內(nèi)
    name_index => 0x000E
    指向常量池第 14 個常量椿胯,為 “this”,所以這個局部變量是 this 指針剃根,指向使用該方法的當前實例
    descriptor_index => 0x000F
    指向常量池第 15 個常量哩盲,為 “Ljvm/HelloWorld”,所以這個 this 指針代表的就是類 HelloWorld 的實例
    index => 0x0000
    表示該局部變量在棧幀局部變量表中 Slot 的位置狈醉,可知為第一個 Slot

2.8.3.4 ConstantValue 屬性

該屬性在 2.6.2 對字段 “text” 的解析中已經(jīng)提到廉油,具體的作用是通知虛擬機初始化靜態(tài)變量

目前類變量的初始化有兩種方式

  • 使用 ConstantValue 屬性
    基本類型或者 java.lang.String,同時被 static 和 final 修飾的變量(又稱為常量)
  • 在類構(gòu)造函數(shù) <clinit>
    不是常量苗傅,或者不是基本類型或 java.lang.String
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末抒线,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子渣慕,更是在濱河造成了極大的恐慌嘶炭,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逊桦,死亡現(xiàn)場離奇詭異眨猎,居然都是意外死亡,警方通過查閱死者的電腦和手機强经,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門睡陪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人匿情,你說我怎么就攤上這事兰迫。” “怎么了炬称?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵汁果,是天一觀的道長。 經(jīng)常有香客問我转砖,道長须鼎,這世上最難降的妖魔是什么鲸伴? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任府蔗,我火速辦了婚禮,結(jié)果婚禮上汞窗,老公的妹妹穿的比我還像新娘姓赤。我一直安慰自己,他們只是感情好仲吏,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布不铆。 她就那樣靜靜地躺著蝌焚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪誓斥。 梳的紋絲不亂的頭發(fā)上只洒,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天,我揣著相機與錄音劳坑,去河邊找鬼毕谴。 笑死,一個胖子當著我的面吹牛距芬,可吹牛的內(nèi)容都是我干的涝开。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼框仔,長吁一口氣:“原來是場噩夢啊……” “哼舀武!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起离斩,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤银舱,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后跛梗,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體纵朋,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年茄袖,在試婚紗的時候發(fā)現(xiàn)自己被綠了操软。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡宪祥,死狀恐怖聂薪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蝗羊,我是刑警寧澤藏澳,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站耀找,受9級特大地震影響翔悠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜野芒,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一蓄愁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧狞悲,春花似錦撮抓、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽站超。三九已至,卻和暖如春乖酬,著一層夾襖步出監(jiān)牢的瞬間死相,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工咬像, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留媳纬,地道東北人。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓施掏,卻偏偏與公主長得像钮惠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子七芭,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345

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

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法素挽,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法贸铜,線程的語...
    子非魚_t_閱讀 31,581評論 18 399
  • 一、JVM內(nèi)幕:Java虛擬機詳解(java se 7規(guī)范) 直接上圖辩昆,再逐步解釋阅酪。 上圖顯示的組件分兩個章節(jié)解釋...
    屈小勇閱讀 1,838評論 6 22
  • 這篇文章解釋了Java 虛擬機(JVM)的內(nèi)部架構(gòu)。下圖顯示了遵守Java SE 7 規(guī)范的典型的 JVM 核心內(nèi)...
    飲墨饗書閱讀 645評論 0 1
  • 因上努力,果上隨緣施无,無上清涼辉词。因,果猾骡,無瑞躺。凡事有因就有果,心靜兴想,心凈幢哨,心境。清心襟企,清凈嘱么,清涼⊥绲浚《楚辭·遠游》中解:...
    紫懸閱讀 3,490評論 0 2
  • 剛才一個小小的舉動令我怡然自樂曼振,我是一個手機殼控,我都得不得到底買了多少手機殼了蔚龙,只記得朋友們叫我時常說:“你怎么...
    好心眼怪脾氣閱讀 143評論 0 0