文章目錄
- 前言
- 一、通路和修飾标志
- 二、類索引
- 三、父類索引
- 四、接口計數器
- 五、接口表
- 六、字段計數器
- 七、字段表
前言
上一篇部落格 【Java 虛拟機原理】Class 位元組碼二進制檔案分析 二 ( 常量池位置 | 常量池結構 | tag | info[] | 完整分析位元組碼檔案中的常量池二進制資料 ) ;
分析到 Student.class 位元組碼檔案的如下選中部分是常量池資料 ;
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5iMxgTN0EzMlNmMhFGNzQGZxYzXwMTM0UTMxEzLcFDMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
本篇部落格中 , 繼續向後分析 位元組碼對應資料 ;
分析的原始資料是 【Java 虛拟機原理】Class 位元組碼二進制檔案分析 一 ( 位元組碼檔案附加資訊 | 魔數 | 次版本号 | 主版本号 | 常量池個數 ) 二、位元組碼檔案示例 章節中的 Java 源碼 , Class 位元組碼 , 位元組碼附加資訊 ;
public class Student {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
位元組碼附加資訊 :
D:\jvm>javap -v Student.class
Classfile /D:/jvm/Student.class
Last modified 2021-9-4; size 392 bytes
MD5 checksum 8b9bb897bb8cf2a8addf04be5b7b915f
Compiled from "Student.java"
public class Student
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #4.#17 // java/lang/Object."<init>":()V
#2 = Fieldref #3.#18 // Student.name:Ljava/lang/String;
#3 = Class #19 // Student
#4 = Class #20 // java/lang/Object
#5 = Utf8 name
#6 = Utf8 Ljava/lang/String;
#7 = Utf8 <init>
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 getName
#12 = Utf8 ()Ljava/lang/String;
#13 = Utf8 setName
#14 = Utf8 (Ljava/lang/String;)V
#15 = Utf8 SourceFile
#16 = Utf8 Student.java
#17 = NameAndType #7:#8 // "<init>":()V
#18 = NameAndType #5:#6 // name:Ljava/lang/String;
#19 = Utf8 Student
#20 = Utf8 java/lang/Object
{
public Student();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0
public java.lang.String getName();
descriptor: ()Ljava/lang/String;
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #2 // Field name:Ljava/lang/String;
4: areturn
LineNumberTable:
line 5: 0
public void setName(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: putfield #2 // Field name:Ljava/lang/String;
5: return
LineNumberTable:
line 9: 0
line 10: 5
}
SourceFile: "Student.java"
一、通路和修飾标志
access_flags ( 通路和修飾标志 ) : 常量池後面的
2
2
2 位就是 通路和修飾标志 ; 通路 和 修飾标志
00 21
; 表示 類 / 接口 的 通路權限 / 基礎屬性 ;
根據下面兩個表解讀 通路和修飾标志 ;
通路和修飾标志
00 21
; 這是根據上述表格中的值進行位運算得到的 ;
這是 ACC_SUPER
0x0200
和 ACC_PUBLIC
0x0001
兩個值進行或運算 , 得出的值
0x0021
;
在 位元組碼附加資訊 中的 次版本号 , 主版本号 , 後跟着的就是 通路和修飾标志
ACC_PUBLIC, ACC_SUPER
, 就是根據這裡的
2
2
2 個位元組的資訊得出的 ;
public class Student
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
二、類索引
this_class ( 類索引 ) : 在 access_flags ( 通路和修飾标志 ) 後面的
2
2
2 位元組就是 類索引 ; 這個值必須是 常量池 中的有效索引值 , 并且還要是 CONSTANT_Class_Info 類型的常量 ;
值為
00 03
, 也就是對應常量池中的
#3
常量 ;
常量池中的
#3
索引是 Student 類 ; 參考 【Java 虛拟機原理】Class 位元組碼二進制檔案分析 二 ( 常量池位置 | 常量池結構 | tag | info[] | 完整分析位元組碼檔案中的常量池二進制資料 ) 二、常量池位元組碼檔案分析 3、常量池 #3 常量分析 章節 ;
Constant pool:
#1 = Methodref #4.#17 // java/lang/Object."<init>":()V
#2 = Fieldref #3.#18 // Student.name:Ljava/lang/String;
#3 = Class #19 // Student
後面的位元組碼資料, 基本都是指向了常量池中的一些引用 ;
三、父類索引
super_class ( 父類索引 ) : 在 this_class ( 類索引 ) 後面的
2
2
2 位元組就是 父類索引 ; 這個值必須是 常量池 中的有效索引值 , 并且還要是 CONSTANT_Class_Info 類型的常量 ;
值為
00 04
, 也就是對應常量池中的
#3
常量 ;
常量池中的
#4
索引是 java/lang/Object 類 ; 參考 【Java 虛拟機原理】Class 位元組碼二進制檔案分析 二 ( 常量池位置 | 常量池結構 | tag | info[] | 完整分析位元組碼檔案中的常量池二進制資料 ) 二、常量池位元組碼檔案分析 4、常量池 #4 常量分析 章節 ;
Constant pool:
#4 = Class #20 // java/lang/Object
後面的位元組碼資料, 基本都是指向了常量池中的一些引用 ;
四、接口計數器
interface_count ( 接口計數器 ) : 在 super_class ( 父類索引 ) 後面的
2
2
2 位元組就是 接口計數器 ; 表示 目前 類 的 直接 父類 或 接口 數 , 間接的不算 ;
值為
00 00
, 也就是沒有實作任何接口 , 接口數為
0 ;
五、接口表
interfaces ( 接口表 ) : 這裡注意 , 如果接口個數大于
0 才有字段表 , 如果接口個數為
0 , 根本沒有這個字段 ;
本示例中 接口個數為
0 , 後面沒有字段表 , 接口計數器 後面的
2
2
2 位元組是 字段計數器 ;
六、字段計數器
fields_count ( 字段計數器 ) : 在 接口計數器 / 接口表 後面的
2
2
2 位元組就是 字段計數器 ; 表示 目前 類 的 字段 數 ;
七、字段表