JVM-解析常量池


  Java最顯著的特點就是"Write Once, Run Anywhere", 這全是因為虛擬機JVM的存在,使得Java代碼的運行可以不受操作系統的限制。不論是Java語言的代碼還是其他語言的代碼,最終都可以編譯成字節碼.Class文件,虛擬機並不關心文件來自什么語言,只要符合Class文件的格式,可以在虛擬機中運行就行。

  Class文件中只要兩種數據機構:無符號數無符號數u1,u2,u4,u8分別代表1個字節,2個字節,4個字節和8個字節;是由多個無符號數或其他表構成的復合數據類型,和C語言中的結構體類似。整個Class文件就是由以下的數據項構成的:

類型 名稱 數量
u4 magic 1
u2 minor_version 1
u2 major_version 1
u2 constant_pool_count 1
cp_info constant_pool constant_pool_count - 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 attribute_count 1
attribute_info attributes attributes_count

下面是十六進制編輯器wxmedit打開的一個Class文件

  前四個字節CA FE BA BE 稱為魔數(Magic Number)對應u4類型的magic,魔數是用來判定當前的文件是否為Class文件

  第五和第六個字節 00 00 代表次版本號(Minor Version),第七和第八個字節00 34代表主版本號(Major Version)52,對應JDK52.0

  主版本號之后就是常量池(Constant Pool)的入口,是占用Class文件最大的項目,常量池的大小是不固定的,所以在常量池入口處首先看到的是常量池的計數值(constant_pool_count)00 36 ,但常量池的容量不是從0而是從1開始計數的,所以對應常量池有54-1=53個常量項

  常量池中主要存放兩大類常量:字面量和符號引用;字面量好比Java中的文本字符串和被聲明的final常量,符號引用主要包括了三類常量:類和接口的全限定名,字段的名稱和描述符,方法的名稱和描述符

  之所以存在常量池是因為Java代碼在編譯的時候沒有"連接" 

  C 語言: 編譯->鏈接->.exe->執行
    函數A調用函數B,在鏈接時會直接在函數A中記錄函數B的地址。
  Java : 編譯->.class ->裝載執行
     類 Employee 中使用了另外一個類 Department,在Employee.class 中只保存類Department的名稱, 而不會保留類Department的“地址”。虛擬機運行的時候需要從常量池獲得對應的符號引用,在類創建的時候翻譯並解析到具體的內存之中。

    下面是常量池中包含的項目類型

 

常量池中數據項類型 類型標志 類型描述
CONSTANT_Utf8 1 UTF-8編碼的Unicode字符串
CONSTANT_Integer 3 int類型字面值
CONSTANT_Float 4 float類型字面值
CONSTANT_Long 5 long類型字面值
CONSTANT_Double 6 double類型字面值
CONSTANT_Class 7 對一個類或接口的符號引用
CONSTANT_String 8 String類型字面值
CONSTANT_Fieldref 9 對一個字段的符號引用
CONSTANT_Methodref 10 對一個類中聲明的方法的符號引用
CONSTANT_InterfaceMethodref 11 對一個接口中聲明的方法的符號引用
CONSTANT_NameAndType 12 對一個字段或方法的部分符號引用

 

 

 

   

 

 

 

 

 

 

 

 

 

 

 

常量池的第一項常量,標志位tag =  07,對應 CONSTANT_Class 類型

 

類型 名稱 數量
u1 tag 1
u2 name_index 1

 

 

   

 

 

 

 標志位之后是name_index = 00 02,指向常量池中的第二項, tag = 01,表示CONSTANT_Utf8

 

類型 名稱 數量
u1 tag 1
u2 length 1
u1 bytes length

  

 

 

 

 

第二項常量中 00 33 十進制表示51,即length=51,即此UTF8編碼的字符串長度是51個字節

 

 

  第三項常量tag = 07, 可知是CONSTANT_Class 類型 ,name_index = 00 04, 指向第四項常量

  第四項常量tag = 01, 可知是CONSTANT_Utf8類型,length = 16 (00 10)轉換而來

  其他項的解析和之前的類似,對照具體的常量的結構來分析

 

    常量

 項目     

  類型  

描述

 

CONSTANT_Utf8

tag

u1

值為1

length

u2

UF-8編碼的字符串占用的字節數

bytes

u1

長度為length的UTF-8編碼的字符串

 

CONSTANT_Integer

tag

u1

值為3

bytes

u4

按照高位在前存儲的int值

 

CONSTANT_Float

tag

u1

值為4

bytes

u4

按照高位在前存儲的float值

 

CONSTANT_Long

tag

u1

值為5

bytes

u8

按照高位在前存儲的long值

 

CONSTANT_Double

tag

u1

值為6

bytes

u8

按照高位在前存儲的double值

 

CONSTANT_Class

tag

u1

值為7

index

u2

指向全限定名常量項的索引

 

CONSTANT_String

tag

u1

值為8

index

u2

指向字符串字面量的索引

 

CONSTANT_Fieldref

tag

u1

值為9

index

u2

指向聲明字段的類或接口描述符CONSTANT_Class_info的索引項

index

u2

指向字段名稱及類型描述符CONSTANT_NameAndType_info的索引項

 

CONSTANT_Methodref

tag

u1

值為10

index

u2

指向聲明方法的類描述符CONSTANT_Class_info的索引項

index

u2

指向方法名稱及類型描述符CONSTANT_NameAndType_info的索引項

 

CONSTANT_InrerfaceMethodref

tag

u1

值為11

index

u2

指向聲明方法的接口描述符CONSTANT_Class_info的索引項

index

u2

指向方法名稱及類型描述符CONSTANT_NameAndType_info的索引項

 

CONSTANT_NameAndType

tag

u1

值為12

index

u2

指向字段或方法名稱常量項目的索引

index

u2

指向該字段或方法描述符常量項的索引


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM