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_infoCONSTANT_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 等)
  1. 魔数

​ 0000000 ca fe ba be 00 00 00 34 00 1f 0a 00 06 00 11 09

​ 4 个字节,这是 Java 字节码文件的约定的类型,JVM 根据魔数判断是否为字节码文件

  1. 次版本号

​ 0000000 ca fe ba be 00 00 00 34 00 1f 0a 00 06 00 11 09

​ 2 个字节次版本号,转为 10 进制等于 0

  1. 主版本号

​ 0000000 ca fe ba be 00 00 00 34 00 1f 0a 00 06 00 11 09

​ 2 个字节主版本号,转为 10 进制等于 52,代表 Java8

  1. 常量池计数

​ 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对应 i6e对应 n69对应 i74对应 t3e对应 >,完整字符串为:<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对应 C6f对应 o64对应 d65对应 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对应 L69对应 i6e对应 n65对应 e4e对应 N75对应 u6d对应 m62对应 b65对应 e72对应 r54对应 T61对应 a62对应 b6c对应 l65对应 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对应 m61对应 a69对应 i6e对应 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对应 L6a对应 j61对应 a76对应 v61对应 a2f对应 /6c对应 l61对应 a6e对应 n67对应 g2f对应 /53对应 S74对应 t72对应 r69对应 i6e对应 n67对应 g3b对应 ;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对应 M65对应 e74对应 t68对应 h6f对应 o64对应 d50对应 P61对应 a72对应 r61对应 a6d对应 m65对应 e74对应 t65对应 e72对应 r73对应 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对应 a72对应 r67对应 g73对应 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对应 S6f对应 o75对应 u72对应 r63对应 c65对应 e46对应 F69对应 i,,6c对应 l65对应 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对应 H65对应 e6c对应 l6c对应 l6f对应 o57对应 W6f对应 o72对应 r6c对应 l64对应 d2e对应 .6a对应 j61对应 a76对应 v61对应 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对应 h65对应 e6c对应 l6c对应 l6f对应 o20对应 sp等同于空格,77对应 w6f对应 o72对应 r6c对应 l64对应 d21对应 !,完整字符串为: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对应 c6e对应 n2f对应 /7a对应 z68对应 h65对应 e2f对应 /48对应 H65对应 e6c对应 l6c对应 l6f对应 o57对应 W6f对应 o72对应 r6c对应 l64对应 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对应 j61对应 a76对应 v61对应 a2f对应 /6c对应 l61对应 a6e对应 n67对应 g2f对应 /4f对应 O62对应 b6a对应 j65对应 e63对应 c74对应 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对应 j61对应 a76对应 v61对应 a2f对应 /6c对应 l61对应 a6e对应 n67对应 g2f对应 /53对应 S79对应 y73对应 s74对应 t65对应 e6d对应 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对应 o75对应 u74对应 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对应 L6a对应 j61对应 a76对应 v61对应 a2f对应 /69对应 i6f对应 o2f对应 /50对应 P72对应 r69对应 i6e对应 n74对应 t53对应 S74对应 t72对应 r65对应 e61对应 a6d对应 m3b对应 ;,完整字符串为: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对应 j61对应 a76对应 v61对应 a2f对应 /69对应 i6f对应 o2f对应 /50对应 P72对应 r69对应 i6e对应 n74对应 t53对应 S74对应 t72对应 r65对应 e61对应 a6d对应 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对应 p72对应 r69对应 i6e对应 n74对应 t6c对应 l6e对应 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对应 L6a对应 j61对应 a76对应 v61对应 a2f对应 /6c对应 l61对应 a6e对应 n67对应 g2f对应 /53对应 S74对应 t72对应 r69对应 i6e对应 n67对应 g3b对应 ;29对应 )56对应 V,完整字符串为:(Ljava/lang/String;)V

  1. 访问标志

​ 0000520 72 69 6e 67 3b 29 56 00 21 00 05 00 06 00 00 00

​ 2 个字节,这里不转为 16 进制。因为访问修饰符的表也是以 16 进制进行表示的,直接根据表格组合即可。21 等于 0x0001 + 0x0020,即由 ACC_PUBLICACC_SUPER 修饰。表示这是一个 public 类,并且启用了标准的 super 调用语义(即普通 Java 类的标准行为)。这是绝大多数普通 public 类的典型标志组合

  1. 本类索引

​ 0000520 72 69 6e 67 3b 29 56 00 21 00 05 00 06 00 00 00

​ 2 个字节,转为 10 进制是 5,代表 第 #5 项

  1. 父类索引

​ 0000520 72 69 6e 67 3b 29 56 00 21 00 05 00 06 00 00 00

​ 2 个字节,转为 10 进制是 6,代表 第 #6 项

  1. 接口数量

​ 0000520 72 69 6e 67 3b 29 56 00 21 00 05 00 06 00 00 00

​ 2 个字节,转为 10 进制是 0,表示没有实现接口

  1. 字段数量

​ 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,表示没有字段

  1. 方法数量

​ 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_PUBLICACC_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 代表没有表示

​ 至此第二个方法分析结束

  1. 属性数量

​ 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

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐