Java 字节码解析
Java8 中,HelloWorld.java 类
package cn.zhe;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("hello world!");
}
}
该类通过 javac -parameters -d . HelloWorld.java编译后的字节码
0000000 ca fe ba be 00 00 00 34 00 1f 0a 00 06 00 11 09
0000020 00 12 00 13 08 00 14 0a 00 15 00 16 07 00 17 07
0000040 00 18 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29
0000060 56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e
0000100 75 6d 62 65 72 54 61 62 6c 65 01 00 04 6d 61 69
0000120 6e 01 00 16 28 5b 4c 6a 61 76 61 2f 6c 61 6e 67
0000140 2f 53 74 72 69 6e 67 3b 29 56 01 00 10 4d 65 74
0000160 68 6f 64 50 61 72 61 6d 65 74 65 72 73 01 00 04
0000200 61 72 67 73 01 00 0a 53 6f 75 72 63 65 46 69 6c
0000220 65 01 00 0f 48 65 6c 6c 6f 57 6f 72 6c 64 2e 6a
0000240 61 76 61 0c 00 07 00 08 07 00 19 0c 00 1a 00 1b
0000260 01 00 0c 68 65 6c 6c 6f 20 77 6f 72 6c 64 21 07
0000300 00 1c 0c 00 1d 00 1e 01 00 11 63 6e 2f 7a 68 65
0000320 2f 48 65 6c 6c 6f 57 6f 72 6c 64 01 00 10 6a 61
0000340 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 01 00
0000360 10 6a 61 76 61 2f 6c 61 6e 67 2f 53 79 73 74 65
0000400 6d 01 00 03 6f 75 74 01 00 15 4c 6a 61 76 61 2f
0000420 69 6f 2f 50 72 69 6e 74 53 74 72 65 61 6d 3b 01
0000440 00 13 6a 61 76 61 2f 69 6f 2f 50 72 69 6e 74 53
0000460 74 72 65 61 6d 01 00 07 70 72 69 6e 74 6c 6e 01
0000500 00 15 28 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74
0000520 72 69 6e 67 3b 29 56 00 21 00 05 00 06 00 00 00
0000540 00 00 02 00 01 00 07 00 08 00 01 00 09 00 00 00
0000560 1d 00 01 00 01 00 00 00 05 2a b7 00 01 b1 00 00
0000600 00 01 00 0a 00 00 00 06 00 01 00 00 00 03 00 09
0000620 00 0b 00 0c 00 02 00 09 00 00 00 25 00 02 00 01
0000640 00 00 00 09 b2 00 02 12 03 b6 00 04 b1 00 00 00
0000660 01 00 0a 00 00 00 0a 00 02 00 00 00 05 00 08 00
0000700 06 00 0d 00 00 00 05 01 00 0e 00 00 00 01 00 0f
0000720 00 00 00 02 00 10
0000726
第一列 0000000、0000020… 是每行的起始偏移量,偏移量是 8 进制表示,后面的字节码是 16 进制表示
以下是 ClassFile 的定义
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
u4、u2 分别代表无符号 4 个字节、无符号 2 个字节。字节码中 2 个 16 进制的字符是对应 1 个字节。因为 16 进制的字符范围是:0 ~ f,f 在 10 进制中是 15,15 用 2 进制表示是 1111,也就是 1 个16 进制的字符需要用 4 位 2 进制来表示,2 个 16 进制的字符需要用 8 位 2 进制表示,8 位对应的也就是 1 个字节。
以下是常量池标签,用来分析常量池内容(Value 值是 10 进制表示的)
| Constant Type | Value |
|---|---|
CONSTANT_Class |
7 |
CONSTANT_Fieldref |
9 |
CONSTANT_Methodref |
10 |
CONSTANT_InterfaceMethodref |
11 |
CONSTANT_String |
8 |
CONSTANT_Integer |
3 |
CONSTANT_Float |
4 |
CONSTANT_Long |
5 |
CONSTANT_Double |
6 |
CONSTANT_NameAndType |
12 |
CONSTANT_Utf8 |
1 |
CONSTANT_MethodHandle |
15 |
CONSTANT_MethodType |
16 |
CONSTANT_InvokeDynamic |
18 |
其中每个标签的结构如下
CONSTANT_Class_info {
u1 tag;
u2 name_index;
}
CONSTANT_Fieldref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
CONSTANT_Methodref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
CONSTANT_InterfaceMethodref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
CONSTANT_String_info {
u1 tag;
u2 string_index;
}
CONSTANT_Integer_info {
u1 tag;
u4 bytes;
}
CONSTANT_Float_info {
u1 tag;
u4 bytes;
}
CONSTANT_Long_info {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}
CONSTANT_Double_info {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}
CONSTANT_NameAndType_info {
u1 tag;
u2 name_index;
u2 descriptor_index;
}
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
CONSTANT_MethodHandle_info {
u1 tag;
u1 reference_kind;
u2 reference_index;
}
CONSTANT_MethodType_info {
u1 tag;
u2 descriptor_index;
}
CONSTANT_InvokeDynamic_info {
u1 tag;
u2 bootstrap_method_attr_index;
u2 name_and_type_index;
}
以下是类访问修饰符和属性修饰符对照表,访问修饰符 value 是 16 进制表示的,字节码中的值可能是多项进行的组合,比如:00 21 = 0x0001 + 0x0020
| Flag Name | Value | Interpretation |
|---|---|---|
ACC_PUBLIC |
0x0001 | Declared public; may be accessed from outside its package. |
ACC_FINAL |
0x0010 | Declared final; no subclasses allowed. |
ACC_SUPER |
0x0020 | Treat superclass methods specially when invoked by the invokespecial instruction. |
ACC_INTERFACE |
0x0200 | Is an interface, not a class. |
ACC_ABSTRACT |
0x0400 | Declared abstract; must not be instantiated. |
ACC_SYNTHETIC |
0x1000 | Declared synthetic; not present in the source code. |
ACC_ANNOTATION |
0x2000 | Declared as an annotation type. |
ACC_ENUM |
0x4000 | Declared as an enum type. |
方法访问修饰符和属性标志,访问修饰符 value 是 16 进制表示的,字节码中的值可能是多项进行的组合,比如:
| Flag Name | Value | Interpretation |
|---|---|---|
ACC_PUBLIC |
0x0001 | Declared public; may be accessed from outside its package. |
ACC_PRIVATE |
0x0002 | Declared private; accessible only within the defining class. |
ACC_PROTECTED |
0x0004 | Declared protected; may be accessed within subclasses. |
ACC_STATIC |
0x0008 | Declared static. |
ACC_FINAL |
0x0010 | Declared final; must not be overridden (§5.4.5). |
ACC_SYNCHRONIZED |
0x0020 | Declared synchronized; invocation is wrapped by a monitor use. |
ACC_BRIDGE |
0x0040 | A bridge method, generated by the compiler. |
ACC_VARARGS |
0x0080 | Declared with variable number of arguments. |
ACC_NATIVE |
0x0100 | Declared native; implemented in a language other than Java. |
ACC_ABSTRACT |
0x0400 | Declared abstract; no implementation is provided. |
ACC_STRICT |
0x0800 | Declared strictfp; floating-point mode is FP-strict. |
ACC_SYNTHETIC |
0x1000 | Declared synthetic; not present in the source code. |
参数访问修饰符,访问修饰符 value 是 16 进制表示的,字节码中的值可能是多项进行的组合,比如:
| Flag Name | Value | Interpretation |
|---|---|---|
ACC_FINAL |
0x0010 | Indicates that the formal parameter is declared final in the source code and may not be reassigned within the method body. |
ACC_SYNTHETIC |
0x1000 | Indicates that the formal parameter was not explicitly declared in the source code and was generated by the compiler for implementation purposes. |
ACC_MANDATED |
0x8000 | Indicates that the formal parameter is implicitly declared by the Java language specification and is required to be present, even though it does not appear in the source code. |
根据 ClassFile 定义,得到以下表格
| 序号 | 字段名(英文) | 中文名称 | 大小(字节) | 说明 |
|---|---|---|---|---|
| 1 | magic |
魔数 | 4 | 固定值 0xcafebabe,用于识别 Class 文件 |
| 2 | minor_version |
次版本号 | 2 | 类文件的次要版本号(通常为 0) |
| 3 | major_version |
主版本号 | 2 | 如 52 = Java 8,61 = Java 17,65 = Java 21 等 |
| 4 | constant_pool_count |
常量池计数 | 2 | 表示常量池项数量 +1(索引从 1 开始,实际项数 = count - 1) |
| 5 | constant_pool[] |
常量池 | 可变 | 包含 constant_pool_count - 1 个常量项(如 CONSTANT_Class_info、CONSTANT_Utf8_info 等),每项长度不固定 |
| 6 | access_flags |
访问标志 | 2 | 描述类/接口的访问权限和属性(如 ACC_PUBLIC, ACC_FINAL, ACC_INTERFACE 等) |
| 7 | this_class |
本类索引 | 2 | 指向常量池中一个 CONSTANT_Class_info,表示当前类的全限定名 |
| 8 | super_class |
父类索引 | 2 | 指向常量池中一个 CONSTANT_Class_info,表示直接父类;若为 java.lang.Object,则值为 0(但 Object 自身的 super_class 也为 0) |
| 9 | interfaces_count |
接口数量 | 2 | 当前类直接实现(或继承)的接口数量 |
| 10 | interfaces[] |
接口索引表 | 2 × interfaces_count |
每个元素是常量池索引,指向一个 CONSTANT_Class_info,表示一个接口 |
| 11 | fields_count |
字段数量 | 2 | 当前类/接口中显式声明的字段数量(不含继承字段) |
| 12 | fields[] |
字段表 | 可变 | 每个字段包含自己的 access_flags、名称索引、描述符索引和属性表 |
| 13 | methods_count |
方法数量 | 2 | 当前类/接口中显式声明的方法数量(不含继承方法) |
| 14 | methods[] |
方法表 | 可变 | 每个方法包含 access_flags、名称索引、描述符索引及属性(如 Code 属性) |
| 15 | attributes_count |
类属性数量 | 2 | 类级别的属性数量(非字段/方法属性) |
| 16 | attributes[] |
类属性表 | 可变 | 每个属性包含属性名索引、属性长度和具体数据(如 SourceFile, InnerClasses, BootstrapMethods 等) |
- 魔数
0000000 ca fe ba be 00 00 00 34 00 1f 0a 00 06 00 11 09
4 个字节,这是 Java 字节码文件的约定的类型,JVM 根据魔数判断是否为字节码文件
- 次版本号
0000000 ca fe ba be 00 00 00 34 00 1f 0a 00 06 00 11 09
2 个字节次版本号,转为 10 进制等于 0
- 主版本号
0000000 ca fe ba be 00 00 00 34 00 1f 0a 00 06 00 11 09
2 个字节主版本号,转为 10 进制等于 52,代表 Java8
- 常量池计数
0000000 ca fe ba be 00 00 00 34 00 1f 0a 00 06 00 11 09
2 个字节,转为 10 进制等于 31,根据 ClassFile 定义,常量池长度要减 1,也就是只有 30 项
0000000 ca fe ba be 00 00 00 34 00 1f 0a 00 06 00 11 09
第 #1 项,0a,转为 10 进制是 10,结合 常量池标签,数字 10 对应的是 CONSTANT_Methodref,再参考该标签的结构,包含 2 个字节的类信息的索引(u2 class_index)、2 个字节的名称和类型信息的索引(u2 name_and_type_index)
0000000 ca fe ba be 00 00 00 34 00 1f 0a 00 06 00 11 09
类信息的索引,转为 10 进制是 6,代表 第 #6 项
0000000 ca fe ba be 00 00 00 34 00 1f 0a 00 06 00 11 09
名称和类型信息的索引,转为 10 进制是 17,代表 第 #17 项
0000000 ca fe ba be 00 00 00 34 00 1f 0a 00 06 00 11 09
第 #2 项,09,转为 10 进制是 9,结合 常量池标签,数字 9 对应的是 CONSTANT_Fieldref,再参考该标签的结构,包含 2 个字节的类信息的索引(u2 class_index)、2 个字节的名称和类型信息的索引(u2 name_and_type_index)
0000020 00 12 00 13 08 00 14 0a 00 15 00 16 07 00 17 07
类信息的索引,转为 10 进制是 18,代表 第 #18 项
0000020 00 12 00 13 08 00 14 0a 00 15 00 16 07 00 17 07
名称和类型信息的索引,转为 10 进制是 19,代表 第# 19 项
0000020 00 12 00 13 08 00 14 0a 00 15 00 16 07 00 17 07
第 #3 项,08,转为 10 进制是 8,结合 常量池标签,数字 8 对应的是 CONSTANT_String,再参考该标签的结构,包含 2 个字节的字符串信息的索引(u2 string_index)
0000020 00 12 00 13 08 00 14 0a 00 15 00 16 07 00 17 07
字符串信息的索引,转为 10 进制是 20,代表 第 #20 项
0000020 00 12 00 13 08 00 14 0a 00 15 00 16 07 00 17 07
第 #4 项,0a,转为 10 进制是 10,结合 常量池标签,数字 10 对应的是 CONSTANT_Methodref,再参考该标签的结构,包含 2 个字节的类信息的索引(u2 class_index)、2 个字节的名称和类型信息的索引(u2 name_and_type_index)
0000020 00 12 00 13 08 00 14 0a 00 15 00 16 07 00 17 07
类信息的索引,转为 10 进制是 21,代表 第 #21 项
0000020 00 12 00 13 08 00 14 0a 00 15 00 16 07 00 17 07
名称和类型信息的索引,转为 10 进制是 22,代表 第 #22 项
0000020 00 12 00 13 08 00 14 0a 00 15 00 16 07 00 17 07
第 #5 项,07,转为 10 进制是 7,结合 常量池标签,数字 7 对应的是 CONSTANT_Class,再参考该标签的结构,包含 2 个字节的名称信息的索引(u2 name_index)
0000020 00 12 00 13 08 00 14 0a 00 15 00 16 07 00 17 07
名称信息的索引,转为 10 进制是 23,代表 第 #23 项
0000020 00 12 00 13 08 00 14 0a 00 15 00 16 07 00 17 07
第 #6 项,07,转为 10 进制是 7,结合 常量池标签,数字 7 对应的是 CONSTANT_Class,再参考该标签的结构,包含 2 个字节的名称信息的索引(u2 name_index)
0000040 00 18 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29
名称信息的索引,转为 10 进制是 24,代表 第 #24 项
0000040 00 18 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29
第 #7 项,01,转为 10 进制是 1,结合 常量池标签,数字 1 对应的是 CONSTANT_Utf8,再参考该标签的结构,包含 2 个字节的字符串长度(u2 length)、字符串信息(u1 bytes[length])
0000040 00 18 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29
字符串长度,转为 10 进制是 6,代表字符串长度 6 个字节
0000040 00 18 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29
该字符串内容使用 ASCII 码解析,3c对应 <,69对应 i,6e对应 n,69对应 i,74对应 t,3e对应 >,完整字符串为:<init>,代表类中的构造函数
0000040 00 18 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29
第 #8 项,01,转为 10 进制是 1,结合 常量池标签,数字 1 对应的是 CONSTANT_Utf8,再参考该标签的结构,包含 2 个字节的字符串长度(u2 length)、字符串信息(u1 bytes[length])
0000040 00 18 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29
字符串长度,转为 10 进制是 3,代表字符串长度 3 个字节
0000040 00 18 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29
0000060 56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e
该字符串内容使用 ASCII 码解析,28对应 (,29对应 ),56对应 V,完整字符串为:()V,代表类构造函数的无参
0000060 56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e
第 #9 项,01,转为 10 进制是 1,结合 常量池标签,数字 1 对应的是 CONSTANT_Utf8,再参考该标签的结构,包含 2 个字节的字符串长度(u2 length)、字符串信息(u1 bytes[length])
0000060 56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e
字符串长度,转为 10 进制是 4,代表字符串长度 4 个字节
0000060 56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e
该字符串内容使用 ASCII 码解析,43对应 C,6f对应 o,64对应 d,65对应 e,完整字符串为:Code
0000060 56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e
第 #10 项,01,转为 10 进制是 1,结合 常量池标签,数字 1 对应的是 CONSTANT_Utf8,再参考该标签的结构,包含 2 个字节的字符串长度(u2 length)、字符串信息(u1 bytes[length])
0000060 56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e
字符串长度,转为 10 进制是 15,代表字符串长度 15 个字节
0000060 56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e
0000100 75 6d 62 65 72 54 61 62 6c 65 01 00 04 6d 61 69
该字符串内容使用 ASCII 码解析,4c对应 L,69对应 i,6e对应 n,65对应 e,4e对应 N,75对应 u,6d对应 m,62对应 b,65对应 e,72对应 r,54对应 T,61对应 a,62对应 b,6c对应 l,65对应 e,完整字符串为:LineNumberTable
0000100 75 6d 62 65 72 54 61 62 6c 65 01 00 04 6d 61 69
第 #11 项,01,转为 10 进制是 1,结合 常量池标签,数字 1 对应的是 CONSTANT_Utf8,再参考该标签的结构,包含 2 个字节的字符串长度(u2 length)、字符串信息(u1 bytes[length])
0000100 75 6d 62 65 72 54 61 62 6c 65 01 00 04 6d 61 69
字符串长度,转为 10 进制是 4,代表字符串长度 4 个字节
0000100 75 6d 62 65 72 54 61 62 6c 65 01 00 04 6d 61 69
0000120 6e 01 00 16 28 5b 4c 6a 61 76 61 2f 6c 61 6e 67
该字符串内容使用 ASCII 码解析,6d对应 m,61对应 a,69对应 i,6e对应 n,完整字符串为:main
0000120 6e 01 00 16 28 5b 4c 6a 61 76 61 2f 6c 61 6e 67
第 #12 项,01,转为 10 进制是 1,结合 常量池标签,数字 1 对应的是 CONSTANT_Utf8,再参考该标签的结构,包含 2 个字节的字符串长度(u2 length)、字符串信息(u1 bytes[length])
0000120 6e 01 00 16 28 5b 4c 6a 61 76 61 2f 6c 61 6e 67
字符串长度,转为 10 进制是 22,代表字符串长度 22 个字节
0000120 6e 01 00 16 28 5b 4c 6a 61 76 61 2f 6c 61 6e 67
0000140 2f 53 74 72 69 6e 67 3b 29 56 01 00 10 4d 65 74
该字符串内容使用 ASCII 码解析,28对应 (,5b对应 [,4c对应 L,6a对应 j,61对应 a,76对应 v,61对应 a,2f对应 /,6c对应 l,61对应 a,6e对应 n,67对应 g,2f对应 /,53对应 S,74对应 t,72对应 r,69对应 i,6e对应 n,67对应 g,3b对应 ;,29对应 ),56对应 V,完整字符串为:([Ljava/lang/String;)V
0000140 2f 53 74 72 69 6e 67 3b 29 56 01 00 10 4d 65 74
第 #13 项,01,转为 10 进制是 1,结合 常量池标签,数字 1 对应的是 CONSTANT_Utf8,再参考该标签的结构,包含 2 个字节的字符串长度(u2 length)、字符串信息(u1 bytes[length])
0000140 2f 53 74 72 69 6e 67 3b 29 56 01 00 10 4d 65 74
字符串长度,转为 10 进制是 16,代表字符串长度 16 个字节
0000140 2f 53 74 72 69 6e 67 3b 29 56 01 00 10 4d 65 74
0000160 68 6f 64 50 61 72 61 6d 65 74 65 72 73 01 00 04
该字符串内容使用 ASCII 码解析,4d对应 M,65对应 e,74对应 t,68对应 h,6f对应 o,64对应 d,50对应 P,61对应 a,72对应 r,61对应 a,6d对应 m,65对应 e,74对应 t,65对应 e,72对应 r,73对应 s,完整字符串为:MethodPatameters
0000160 68 6f 64 50 61 72 61 6d 65 74 65 72 73 01 00 04
第 #14 项,01,转为 10 进制是 1,结合 常量池标签,数字 1 对应的是 CONSTANT_Utf8,再参考该标签的结构,包含 2 个字节的字符串长度(u2 length)、字符串信息(u1 bytes[length])
0000160 68 6f 64 50 61 72 61 6d 65 74 65 72 73 01 00 04
字符串长度,转为 10 进制是 4,代表字符串长度 4 个字节
0000200 61 72 67 73 01 00 0a 53 6f 75 72 63 65 46 69 6c
该字符串内容使用 ASCII 码解析,61对应 a,72对应 r,67对应 g,73对应 s,完整字符串为:args
0000200 61 72 67 73 01 00 0a 53 6f 75 72 63 65 46 69 6c
第 #15 项,01,转为 10 进制是 1,结合 常量池标签,数字 1 对应的是 CONSTANT_Utf8,再参考该标签的结构,包含 2 个字节的字符串长度(u2 length)、字符串信息(u1 bytes[length])
0000200 61 72 67 73 01 00 0a 53 6f 75 72 63 65 46 69 6c
字符串长度,转为 10 进制是 10,代表字符串长度 10 个字节
0000200 61 72 67 73 01 00 0a 53 6f 75 72 63 65 46 69 6c
0000220 65 01 00 0f 48 65 6c 6c 6f 57 6f 72 6c 64 2e 6a
该字符串内容使用 ASCII 码解析,53对应 S,6f对应 o,75对应 u,72对应 r,63对应 c,65对应 e,46对应 F,69对应 i,,6c对应 l,65对应 e,完整字符串为:SourceFile
0000220 65 01 00 0f 48 65 6c 6c 6f 57 6f 72 6c 64 2e 6a
第 #16 项,01,转为 10 进制是 1,结合 常量池标签,数字 1 对应的是 CONSTANT_Utf8,再参考该标签的结构,包含 2 个字节的字符串长度(u2 length)、字符串信息(u1 bytes[length])
0000220 65 01 00 0f 48 65 6c 6c 6f 57 6f 72 6c 64 2e 6a
字符串长度,转为 10 进制是 15,代表字符串长度 15 个字节
0000220 65 01 00 0f 48 65 6c 6c 6f 57 6f 72 6c 64 2e 6a
0000240 61 76 61 0c 00 07 00 08 07 00 19 0c 00 1a 00 1b
该字符串内容使用 ASCII 码解析,48对应 H,65对应 e,6c对应 l,6c对应 l,6f对应 o,57对应 W,6f对应 o,72对应 r,6c对应 l,64对应 d,2e对应 .,6a对应 j,61对应 a,76对应 v,61对应 a,完整字符串为:HelloWorld.java
0000240 61 76 61 0c 00 07 00 08 07 00 19 0c 00 1a 00 1b
第 #17 项,0c,转为 10 进制是 12,结合 常量池标签,数字 12 对应的是 CONSTANT_NameAndType,再参考该标签的结构,包含 2 个字节的名称信息的索引(u2 name_index)、2 个字节的描述符的索引(u2 descriptor_index)
0000240 61 76 61 0c 00 07 00 08 07 00 19 0c 00 1a 00 1b
名称信息的索引,转为 10 进制是 7,代表 第 #7 项
0000240 61 76 61 0c 00 07 00 08 07 00 19 0c 00 1a 00 1b
描述符的索引,转为 10 进制是 8,代表 第 #8 项
0000240 61 76 61 0c 00 07 00 08 07 00 19 0c 00 1a 00 1b
第 #18 项,07,转为 10 进制是 7,结合 常量池标签,数字 7 对应的是 CONSTANT_Class,再参考该标签的结构,包含 2 个字节的名称信息的索引(u2 name_index)
0000240 61 76 61 0c 00 07 00 08 07 00 19 0c 00 1a 00 1b
名称信息的索引,转为 10 进制是 25,代表 第 #25 项
0000240 61 76 61 0c 00 07 00 08 07 00 19 0c 00 1a 00 1b
第 #19 项,0c,转为 10 进制是 12,结合 常量池标签,数字 12 对应的是 CONSTANT_NameAndType,再参考该标签的结构,包含 2 个字节的名称信息的索引(u2 name_index)、2 个字节的描述符的索引(u2 descriptor_index)
0000240 61 76 61 0c 00 07 00 08 07 00 19 0c 00 1a 00 1b
名称信息的索引,转为 10 进制是 26,代表 第 #26 项
0000240 61 76 61 0c 00 07 00 08 07 00 19 0c 00 1a 00 1b
描述符的索引,转为 10 进制是 8,代表 第 #27 项
0000260 01 00 0c 68 65 6c 6c 6f 20 77 6f 72 6c 64 21 07
第 #20 项,01,转为 10 进制是 1,结合 常量池标签,数字 1 对应的是 CONSTANT_Utf8,再参考该标签的结构,包含 2 个字节的字符串长度(u2 length)、字符串信息(u1 bytes[length])
0000260 01 00 0c 68 65 6c 6c 6f 20 77 6f 72 6c 64 21 07
字符串长度,转为 10 进制是 12,代表字符串长度 12 个字节
0000260 01 00 0c 68 65 6c 6c 6f 20 77 6f 72 6c 64 21 07
该字符串内容使用 ASCII 码解析,68对应 h,65对应 e,6c对应 l,6c对应 l,6f对应 o,20对应 sp等同于空格,77对应 w,6f对应 o,72对应 r,6c对应 l,64对应 d,21对应 !,完整字符串为:hello world!
0000260 01 00 0c 68 65 6c 6c 6f 20 77 6f 72 6c 64 21 07
第 #21 项,07,转为 10 进制是 7,结合 常量池标签,数字 7 对应的是 CONSTANT_Class,再参考该标签的结构,包含 2 个字节的名称信息的索引(u2 name_index)
0000300 00 1c 0c 00 1d 00 1e 01 00 11 63 6e 2f 7a 68 65
名称信息的索引,转为 10 进制是 28,代表 第 #28 项
0000300 00 1c 0c 00 1d 00 1e 01 00 11 63 6e 2f 7a 68 65
第 #22 项,0c,转为 10 进制是 12,结合 常量池标签,数字 12 对应的是 CONSTANT_NameAndType,再参考该标签的结构,包含 2 个字节的名称信息的索引(u2 name_index)、2 个字节的描述符的索引(u2 descriptor_index)
0000300 00 1c 0c 00 1d 00 1e 01 00 11 63 6e 2f 7a 68 65
名称信息的索引,转为 10 进制是 29,代表 第 #29 项
0000300 00 1c 0c 00 1d 00 1e 01 00 11 63 6e 2f 7a 68 65
描述符的索引,转为 10 进制是 30,代表 第 #30 项
0000300 00 1c 0c 00 1d 00 1e 01 00 11 63 6e 2f 7a 68 65
第 #23 项,01,转为 10 进制是 1,结合 常量池标签,数字 1 对应的是 CONSTANT_Utf8,再参考该标签的结构,包含 2 个字节的字符串长度(u2 length)、字符串信息(u1 bytes[length])
0000300 00 1c 0c 00 1d 00 1e 01 00 11 63 6e 2f 7a 68 65
字符串长度,转为 10 进制是 17,代表字符串长度 17 个字节
0000300 00 1c 0c 00 1d 00 1e 01 00 11 63 6e 2f 7a 68 65
0000320 2f 48 65 6c 6c 6f 57 6f 72 6c 64 01 00 10 6a 61
该字符串内容使用 ASCII 码解析,63对应 c,6e对应 n,2f对应 /,7a对应 z,68对应 h,65对应 e,2f对应 /,48对应 H,65对应 e,6c对应 l,6c对应 l,6f对应 o,57对应 W,6f对应 o,72对应 r,6c对应 l,64对应 d,完整字符串为:cn/zhe/HelloWorld
0000320 2f 48 65 6c 6c 6f 57 6f 72 6c 64 01 00 10 6a 61
第 #24 项,01,转为 10 进制是 1,结合 常量池标签,数字 1 对应的是 CONSTANT_Utf8,再参考该标签的结构,包含 2 个字节的字符串长度(u2 length)、字符串信息(u1 bytes[length])
0000320 2f 48 65 6c 6c 6f 57 6f 72 6c 64 01 00 10 6a 61
字符串长度,转为 10 进制是 16,代表字符串长度 16 个字节
0000320 2f 48 65 6c 6c 6f 57 6f 72 6c 64 01 00 10 6a 61
0000340 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 01 00
该字符串内容使用 ASCII 码解析,6a对应 j,61对应 a,76对应 v,61对应 a,2f对应 /,6c对应 l,61对应 a,6e对应 n,67对应 g,2f对应 /,4f对应 O,62对应 b,6a对应 j,65对应 e,63对应 c,74对应 t,完整字符串为:java/lang/Object
0000340 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 01 00
第 #25 项,01,转为 10 进制是 1,结合 常量池标签,数字 1 对应的是 CONSTANT_Utf8,再参考该标签的结构,包含 2 个字节的字符串长度(u2 length)、字符串信息(u1 bytes[length])
0000340 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 01 00
0000360 10 6a 61 76 61 2f 6c 61 6e 67 2f 53 79 73 74 65
字符串长度,转为 10 进制是 16,代表字符串长度 16 个字节
0000360 10 6a 61 76 61 2f 6c 61 6e 67 2f 53 79 73 74 65
0000400 6d 01 00 03 6f 75 74 01 00 15 4c 6a 61 76 61 2f
该字符串内容使用 ASCII 码解析,6a对应 j,61对应 a,76对应 v,61对应 a,2f对应 /,6c对应 l,61对应 a,6e对应 n,67对应 g,2f对应 /,53对应 S,79对应 y,73对应 s,74对应 t,65对应 e,6d对应 m,完整字符串为:java/lang/System
0000400 6d 01 00 03 6f 75 74 01 00 15 4c 6a 61 76 61 2f
第 #26 项,01,转为 10 进制是 1,结合 常量池标签,数字 1 对应的是 CONSTANT_Utf8,再参考该标签的结构,包含 2 个字节的字符串长度(u2 length)、字符串信息(u1 bytes[length])
0000400 6d 01 00 03 6f 75 74 01 00 15 4c 6a 61 76 61 2f
字符串长度,转为 10 进制是 3,代表字符串长度 3 个字节
0000400 6d 01 00 03 6f 75 74 01 00 15 4c 6a 61 76 61 2f
该字符串内容使用 ASCII 码解析,6f对应 o,75对应 u,74对应 t,完整字符串为:out
0000400 6d 01 00 03 6f 75 74 01 00 15 4c 6a 61 76 61 2f
第 #27 项,01,转为 10 进制是 1,结合 常量池标签,数字 1 对应的是 CONSTANT_Utf8,再参考该标签的结构,包含 2 个字节的字符串长度(u2 length)、字符串信息(u1 bytes[length])
0000400 6d 01 00 03 6f 75 74 01 00 15 4c 6a 61 76 61 2f
字符串长度,转为 10 进制是 21,代表字符串长度 21 个字节
0000400 6d 01 00 03 6f 75 74 01 00 15 4c 6a 61 76 61 2f
0000420 69 6f 2f 50 72 69 6e 74 53 74 72 65 61 6d 3b 01
该字符串内容使用 ASCII 码解析,4c对应 L,6a对应 j,61对应 a,76对应 v,61对应 a,2f对应 /,69对应 i,6f对应 o,2f对应 /,50对应 P,72对应 r,69对应 i,6e对应 n,74对应 t,53对应 S,74对应 t,72对应 r,65对应 e,61对应 a,6d对应 m,3b对应 ;,完整字符串为:Ljava/io/PrintStream;
0000420 69 6f 2f 50 72 69 6e 74 53 74 72 65 61 6d 3b 01
第 #28 项,01,转为 10 进制是 1,结合 常量池标签,数字 1 对应的是 CONSTANT_Utf8,再参考该标签的结构,包含 2 个字节的字符串长度(u2 length)、字符串信息(u1 bytes[length])
0000440 00 13 6a 61 76 61 2f 69 6f 2f 50 72 69 6e 74 53
字符串长度,转为 10 进制是 19,代表字符串长度 19 个字节
0000440 00 13 6a 61 76 61 2f 69 6f 2f 50 72 69 6e 74 53
0000460 74 72 65 61 6d 01 00 07 70 72 69 6e 74 6c 6e 01
该字符串内容使用 ASCII 码解析,6a对应 j,61对应 a,76对应 v,61对应 a,2f对应 /,69对应 i,6f对应 o,2f对应 /,50对应 P,72对应 r,69对应 i,6e对应 n,74对应 t,53对应 S,74对应 t,72对应 r,65对应 e,61对应 a,6d对应 m,完整字符串为:java/io/PrintStream
0000460 74 72 65 61 6d 01 00 07 70 72 69 6e 74 6c 6e 01
第 #29 项,01,转为 10 进制是 1,结合 常量池标签,数字 1 对应的是 CONSTANT_Utf8,再参考该标签的结构,包含 2 个字节的字符串长度(u2 length)、字符串信息(u1 bytes[length])
0000460 74 72 65 61 6d 01 00 07 70 72 69 6e 74 6c 6e 01
字符串长度,转为 10 进制是 7,代表字符串长度 7 个字节
0000460 74 72 65 61 6d 01 00 07 70 72 69 6e 74 6c 6e 01
该字符串内容使用 ASCII 码解析,70对应 p,72对应 r,69对应 i,6e对应 n,74对应 t,6c对应 l,6e对应 n,完整字符串为:println
0000460 74 72 65 61 6d 01 00 07 70 72 69 6e 74 6c 6e 01
第 #30 项,01,转为 10 进制是 1,结合 常量池标签,数字 1 对应的是 CONSTANT_Utf8,再参考该标签的结构,包含 2 个字节的字符串长度(u2 length)、字符串信息(u1 bytes[length])
0000500 00 15 28 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74
字符串长度,转为 10 进制是 21,代表字符串长度 21 个字节
0000500 00 15 28 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74
0000520 72 69 6e 67 3b 29 56 00 21 00 05 00 06 00 00 00
该字符串内容使用 ASCII 码解析,28对应 (,4c对应 L,6a对应 j,61对应 a,76对应 v,61对应 a,2f对应 /,6c对应 l,61对应 a,6e对应 n,67对应 g,2f对应 /,53对应 S,74对应 t,72对应 r,69对应 i,6e对应 n,67对应 g,3b对应 ;,29对应 ),56对应 V,完整字符串为:(Ljava/lang/String;)V
- 访问标志
0000520 72 69 6e 67 3b 29 56 00 21 00 05 00 06 00 00 00
2 个字节,这里不转为 16 进制。因为访问修饰符的表也是以 16 进制进行表示的,直接根据表格组合即可。21 等于 0x0001 + 0x0020,即由 ACC_PUBLIC 和 ACC_SUPER 修饰。表示这是一个 public 类,并且启用了标准的 super 调用语义(即普通 Java 类的标准行为)。这是绝大多数普通 public 类的典型标志组合
- 本类索引
0000520 72 69 6e 67 3b 29 56 00 21 00 05 00 06 00 00 00
2 个字节,转为 10 进制是 5,代表 第 #5 项
- 父类索引
0000520 72 69 6e 67 3b 29 56 00 21 00 05 00 06 00 00 00
2 个字节,转为 10 进制是 6,代表 第 #6 项
- 接口数量
0000520 72 69 6e 67 3b 29 56 00 21 00 05 00 06 00 00 00
2 个字节,转为 10 进制是 0,表示没有实现接口
- 字段数量
0000520 72 69 6e 67 3b 29 56 00 21 00 05 00 06 00 00 00
0000540 00 00 02 00 01 00 07 00 08 00 01 00 09 00 00 00
2 个字节,转为 10 进制是 0,表示没有字段
- 方法数量
0000540 00 00 02 00 01 00 07 00 08 00 01 00 09 00 00 00
2 个字节,转为 10 进制是 2,表示 2 个方法
分析方法,参考方法结构
method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
第一个方法:
0000540 00 00 02 00 01 00 07 00 08 00 01 00 09 00 00 00
2 个字节,访问标志,这里不转为 16 进制。因为访问修饰符的表也是以 16 进制进行表示的,直接根据表格组合即可。1 等于 0x0001,即由 ACC_PUBLIC 修饰。表示这是一个 public 方法
0000540 00 00 02 00 01 00 07 00 08 00 01 00 09 00 00 00
2 个字节,名称索引,转为 10 进制是 7,表示 第 #7 项,<init> 代表构造方法
0000540 00 00 02 00 01 00 07 00 08 00 01 00 09 00 00 00
2 个字节,描述符索引,转为 10 进制是 8,表示 第 #8 项,()V 代表无参
0000540 00 00 02 00 01 00 07 00 08 00 01 00 09 00 00 00
2 个字节,属性数量,转为 10 进制是 1,表示只有 1 个属性
分析属性,再参考属性结构
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
0000540 00 00 02 00 01 00 07 00 08 00 01 00 09 00 00 00
2 个字节,属性名称索引,转为 10 进制是 9,表示 第 #9 项,该属性是 Code
Code 属性结构如下,其中前两个 u2 attribute_name_index 和 u4 attribute_length 是和上面的属性结构一致(分析时不要重复计算)
Code_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 max_stack;
u2 max_locals;
u4 code_length;
u1 code[code_length];
u2 exception_table_length;
{ u2 start_pc;
u2 end_pc;
u2 handler_pc;
u2 catch_type;
} exception_table[exception_table_length];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
0000540 00 00 02 00 01 00 07 00 08 00 01 00 09 00 00 00
0000560 1d 00 01 00 01 00 00 00 05 2a b7 00 01 b1 00 00
4 个字节,属性信息长度,转为 10 进制是 29,代表属性信息长度 29 个字节,分析范围如下
000560 1d 00 01 00 01 00 00 00 05 2a b7 00 01 b1 00 00
0000600 00 01 00 0a 00 00 00 06 00 01 00 00 00 03 00 09
0000560 1d 00 01 00 01 00 00 00 05 2a b7 00 01 b1 00 00
2 个字节,操作数栈最大深度,转为 10 进制是 1
0000560 1d 00 01 00 01 00 00 00 05 2a b7 00 01 b1 00 00
2 个字节,局部变量表大小,转为 10 进制是 1,构造方法的局部变量 this
0000560 1d 00 01 00 01 00 00 00 05 2a b7 00 01 b1 00 00
4 个字节,字节码指令长度,转为 10 进制是 5
0000560 1d 00 01 00 01 00 00 00 05 2a b7 00 01 b1 00 00
参考 Chapter 6. The Java Virtual Machine Instruction Set,分别得到 2a、b7、00 01、b1 的对应内容
| 字节 | 指令 | 说明 |
|---|---|---|
2a |
aload_0 |
将 this(局部变量 0)压入操作数栈 |
b7 |
invokespecial 的 opcode |
接下来 2 字节是操作数 |
00 01 |
操作数 = 常量池索引 #1 | 调用 #1 所指向的方法(通常是 java/lang/Object.<init>:()V) |
b1 |
return |
从 void 方法返回 |
0000560 1d 00 01 00 01 00 00 00 05 2a b7 00 01 b1 00 00
2 个字节,异常表长度,转为 10 进制是 0,表示无异常
0000600 00 01 00 0a 00 00 00 06 00 01 00 00 00 03 00 09
2 个字节,子属性数量,转为 10 进制是 1
再结合属性信息结构
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
0000600 00 01 00 0a 00 00 00 06 00 01 00 00 00 03 00 09
2 个字节,属性名称索引,转为 10 进制是 10,表示 第 #10 项,该子属性是 LineNumberTable
0000600 00 01 00 0a 00 00 00 06 00 01 00 00 00 03 00 09
4 个字节,子属性长度,转为 10 进制是 6,表示 6 个字节
因为子属性是 LineNumberTable,结合其结构再分析
LineNumberTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 line_number_table_length;
{ u2 start_pc;
u2 line_number;
} line_number_table[line_number_table_length];
}
0000600 00 01 00 0a 00 00 00 06 00 01 00 00 00 03 00 09
2 个字节,行记录表长度,转为 10 进制是 1,表示记录了一次 “字节码位置 ↔ 源码行号” 的对应关系
0000600 00 01 00 0a 00 00 00 06 00 01 00 00 00 03 00 09
2 个字节,字节码偏移量,转为 10 进制是 0,表示从字节码偏移 0 开始,start_pc = 0(即 aload_0)
0000600 00 01 00 0a 00 00 00 06 00 01 00 00 00 03 00 09
2 个字节,对应源码行,转为 10 进制是 3,表示源码第三行,System.out.println(...),至此第一个方法分析结束
第二个方法(和第一个方法分析步骤一致):
0000600 00 01 00 0a 00 00 00 06 00 01 00 00 00 03 00 09
2 个字节,访问标志,这里不转为 16 进制。因为访问修饰符的表也是以 16 进制进行表示的,直接根据表格组合即可。1 等于 0x0001,8 等于 0x0008,即由 ACC_PUBLIC 和 ACC_STATIC 修饰。表示这是一个 public static方法
0000620 00 0b 00 0c 00 02 00 09 00 00 00 25 00 02 00 01
2 个字节,名称索引,转为 10 进制是 11,表示 第 #11 项,main 代表 main 方法
0000620 00 0b 00 0c 00 02 00 09 00 00 00 25 00 02 00 01
2 个字节,描述符索引,转为 10 进制是 12,表示 第 #12 项,([Ljava/lang/String;)V 代表字符串数组参数
0000620 00 0b 00 0c 00 02 00 09 00 00 00 25 00 02 00 01
2 个字节,属性数量,转为 10 进制是 2,表示有 2 个属性
分析属性,再参考属性结构
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
0000620 00 0b 00 0c 00 02 00 09 00 00 00 25 00 02 00 01
2 个字节,属性名称索引,转为 10 进制是 9,表示 第 #9 项,该属性是 Code
Code 属性结构如下,其中前两个 u2 attribute_name_index 和 u4 attribute_length 是和上面的属性结构一致(分析时不要重复计算)
Code_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 max_stack;
u2 max_locals;
u4 code_length;
u1 code[code_length];
u2 exception_table_length;
{ u2 start_pc;
u2 end_pc;
u2 handler_pc;
u2 catch_type;
} exception_table[exception_table_length];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
0000620 00 0b 00 0c 00 02 00 09 00 00 00 25 00 02 00 01
4 个字节,属性信息长度,转为 10 进制是 37,代表属性信息长度 37 个字节,分析范围如下
0000620 00 0b 00 0c 00 02 00 09 00 00 00 25 00 02 00 01
0000640 00 00 00 09 b2 00 02 12 03 b6 00 04 b1 00 00 00
0000660 01 00 0a 00 00 00 0a 00 02 00 00 00 05 00 08 00
0000700 06 00 0d 00 00 00 05 01 00 0e 00 00 00 01 00 0f
0000620 00 0b 00 0c 00 02 00 09 00 00 00 25 00 02 00 01
2 个字节,操作数栈最大深度,转为 10 进制是 2
0000620 00 0b 00 0c 00 02 00 09 00 00 00 25 00 02 00 01
2 个字节,局部变量表大小,转为 10 进制是 1,main 方法的局部变量 args
0000640 00 00 00 09 b2 00 02 12 03 b6 00 04 b1 00 00 00
4 个字节,字节码指令长度,转为 10 进制是 9
0000640 00 00 00 09 b2 00 02 12 03 b6 00 04 b1 00 00 00
参考 Chapter 6. The Java Virtual Machine Instruction Set,分别得到 b2、00 02、12、03、b6、00 04、b1 的对应内容
| 字节 | 指令 | 说明 |
|---|---|---|
b2 |
getstatic |
获取静态字段,接下来 2 字节为常量池索引 |
00 02 |
操作数 = 常量池索引 #2 | 加载静态字段 #2,即 java/lang/System.out,并将其引用压入操作数栈 |
12 |
ldc |
将常量池中的常量推入操作数栈,接下来 1 字节为常量池索引 |
03 |
操作数 = 常量池索引 #3 | 加载字符串常量 #3,即 "hello world!",压入操作数栈 |
b6 |
invokevirtual |
调用实例方法(虚方法),接下来 2 字节为常量池索引 |
00 04 |
操作数 = 常量池索引 #4 | 调用 #4 所指向的方法,即 java/io/PrintStream.println:(Ljava/lang/String;)V |
b1 |
return |
从 void 方法返回,结束当前方法执行 |
0000640 00 00 00 09 b2 00 02 12 03 b6 00 04 b1 00 00 00
2 个字节,异常表长度,转为 10 进制是 0,表示无异常
0000640 00 00 00 09 b2 00 02 12 03 b6 00 04 b1 00 00 00
0000660 01 00 0a 00 00 00 0a 00 02 00 00 00 05 00 08 00
2 个字节,子属性数量,转为 10 进制是 1
再结合属性信息结构
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
0000660 01 00 0a 00 00 00 0a 00 02 00 00 00 05 00 08 00
2 个字节,属性名称索引,转为 10 进制是 10,表示 第 #10 项,该子属性是 LineNumberTable
0000660 01 00 0a 00 00 00 0a 00 02 00 00 00 05 00 08 00
4 个字节,子属性长度,转为 10 进制是 10,表示 10 个字节
因为子属性是 LineNumberTable,结合其结构再分析
LineNumberTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 line_number_table_length;
{ u2 start_pc;
u2 line_number;
} line_number_table[line_number_table_length];
}
0000660 01 00 0a 00 00 00 0a 00 02 00 00 00 05 00 08 00
2 个字节,行记录表长度,转为 10 进制是 2,表示记录了 2 次 “字节码位置 ↔ 源码行号” 的对应关系
0000660 01 00 0a 00 00 00 0a 00 02 00 00 00 05 00 08 00
2 个字节,字节码偏移量,转为 10 进制是 0,表示从字节码偏移 0 开始,start_pc = 0(即 getstatic)
0000660 01 00 0a 00 00 00 0a 00 02 00 00 00 05 00 08 00
2 个字节,对应源码行,转为 10 进制是 5,表示源码第 5 行,System.out.println("hello world!");
0000660 01 00 0a 00 00 00 0a 00 02 00 00 00 05 00 08 00
2 个字节,字节码偏移量,转为 10 进制是 8,表示从字节码偏移 8 开始,start_pc = 8(即 return)
0000660 01 00 0a 00 00 00 0a 00 02 00 00 00 05 00 08 00
0000700 06 00 0d 00 00 00 05 01 00 0e 00 00 00 01 00 0f
2 个字节,对应源码行,转为 10 进制是 6,表示源码第 6 行,}
再结合属性信息结构
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
0000700 06 00 0d 00 00 00 05 01 00 0e 00 00 00 01 00 0f
2 个字节,属性名称索引,转为 10 进制是 13,表示 第 #13 项,该属性是 MethodPatameters
0000700 06 00 0d 00 00 00 05 01 00 0e 00 00 00 01 00 0f
5 个字节,子属性长度,转为 10 进制是 5,表示 5 个字节
因为子属性是 MethodPatameters,结合其结构再分析
MethodParameters_attribute {
u2 attribute_name_index;
u4 attribute_length;
u1 parameters_count;
{ u2 name_index;
u2 access_flags;
} parameters[parameters_count];
}
0000700 06 00 0d 00 00 00 05 01 00 0e 00 00 00 01 00 0f
1 个字节,参数数量,转为 10 进制是 1,表示 1 个参数
0000700 06 00 0d 00 00 00 05 01 00 0e 00 00 00 01 00 0f
2 个字节,名称索引,转为 10 进制是 14,表示 第 #14 项,该参数是 args
0000700 06 00 0d 00 00 00 05 01 00 0e 00 00 00 01 00 0f
2 个字节,访问标志,转为 10 进制是 0
访问标志,这里不转为 16 进制。因为访问修饰符的表也是以 16 进制进行表示的,直接根据表格组合即可。0 代表没有表示
至此第二个方法分析结束
- 属性数量
0000700 06 00 0d 00 00 00 05 01 00 0e 00 00 00 01 00 0f
2 个字节,转为 10 进制是 1,表示 1 个属性
再结合属性信息结构
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
0000700 06 00 0d 00 00 00 05 01 00 0e 00 00 00 01 00 0f
2 个字节,属性名称索引,转为 10 进制是 15,表示 第 #15 项,该属性是 SourceFile
再结合属性信息结构
SourceFile_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 sourcefile_index;
}
0000720 00 00 00 02 00 10
4 个字节,属性长度,转为 10 进制是 2
0000720 00 00 00 02 00 10
2 个字节,源文件索引,转为 10 进制是 16,表示 第 #16 项,源文件是 HelloWorld.java
更多推荐




所有评论(0)