java字节码解析入门

java字节码解析入门,从Hello world开始。

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];
}

java源文件

1 public class Test {
2    public static void main(String[] args) {
3        System.out.println("Hello world");
4    }
5 }

class二进制文件

ca fe ba be 00 00 00 34 00 22 0a 00 06 00 14 09
00 15 00 16 08 00 17 0a 00 18 00 19 07 00 1a 07
00 1b 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29
56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e
75 6d 62 65 72 54 61 62 6c 65 01 00 12 4c 6f 63
61 6c 56 61 72 69 61 62 6c 65 54 61 62 6c 65 01
00 04 74 68 69 73 01 00 06 4c 54 65 73 74 3b 01
00 04 6d 61 69 6e 01 00 16 28 5b 4c 6a 61 76 61
2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 29 56 01
00 04 61 72 67 73 01 00 13 5b 4c 6a 61 76 61 2f
6c 61 6e 67 2f 53 74 72 69 6e 67 3b 01 00 0a 53
6f 75 72 63 65 46 69 6c 65 01 00 09 54 65 73 74
2e 6a 61 76 61 0c 00 07 00 08 07 00 1c 0c 00 1d
00 1e 01 00 0b 48 65 6c 6c 6f 20 77 6f 72 6c 64
07 00 1f 0c 00 20 00 21 01 00 04 54 65 73 74 01
00 10 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65
63 74 01 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 53
79 73 74 65 6d 01 00 03 6f 75 74 01 00 15 4c 6a
61 76 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72 65
61 6d 3b 01 00 13 6a 61 76 61 2f 69 6f 2f 50 72
69 6e 74 53 74 72 65 61 6d 01 00 07 70 72 69 6e
74 6c 6e 01 00 15 28 4c 6a 61 76 61 2f 6c 61 6e
67 2f 53 74 72 69 6e 67 3b 29 56 00 21 00 05 00
06 00 00 00 00 00 02 00 01 00 07 00 08 00 01 00
09 00 00 00 2f 00 01 00 01 00 00 00 05 2a b7 00
01 b1 00 00 00 02 00 0a 00 00 00 06 00 01 00 00
00 01 00 0b 00 00 00 0c 00 01 00 00 00 05 00 0c
00 0d 00 00 00 09 00 0e 00 0f 00 01 00 09 00 00
00 37 00 02 00 01 00 00 00 09 b2 00 02 12 03 b6
00 04 b1 00 00 00 02 00 0a 00 00 00 0a 00 02 00
00 00 03 00 08 00 04 00 0b 00 00 00 0c 00 01 00
00 00 09 00 10 00 11 00 00 00 01 00 12 00 00 00
02 00 13

class二进制文件解析

u4 magic;

占4字节(u4代表4字节、u2代表2字节),类文件标识:cafebabe 咖啡宝贝 👶

  • ca fe ba be 00 00 00 34 00 22 0a 00 06 00 14 09
  • 00 15 00 16 08 00 17 0a 00 18 00 19 07 00 1a 07

u2 minor_version;

占2字节,次版本:0000 minor_version = 0

  • ca fe ba be 00 00 00 34 00 22 0a 00 06 00 14 09
  • 00 15 00 16 08 00 17 0a 00 18 00 19 07 00 1a 07

u2 major_version;

占2字节,主版本:0034 major_version = 52

  • ca fe ba be 00 00 00 34 00 22 0a 00 06 00 14 09
  • 00 15 00 16 08 00 17 0a 00 18 00 19 07 00 1a 07

u2 constant_pool_count;

占2字节,constant_pool_count 项的值等于 constant_pool 表中的条目数加一。 如果 constant_pool 索引大于零且小于 constant_pool_count,则认为它是有效的。

十六进制值:0022 constant_pool_count = 34。表示常量池共有33项。

  • ca fe ba be 00 00 00 34 00 22 0a 00 06 00 14 09
  • 00 15 00 16 08 00 17 0a 00 18 00 19 07 00 1a 07

cp_info constant_pool[constant_pool_count-1];

常量池表,共有33项。constant_pool表索引从1到constant_pool_count - 1。
常量池每项结构如下:
cp_info

cp_info {
    u1 tag;
    u1 info[];
} 

通过一个字节(u1 tag)标识每项类型。

常量类型tag值
CONSTANT_Class7
CONSTANT_Fieldref9
CONSTANT_Methodref10
CONSTANT_InterfaceMethodref11
CONSTANT_String8
CONSTANT_Integer3
CONSTANT_Float4
CONSTANT_Long5
CONSTANT_Double6
CONSTANT_NameAndType12
CONSTANT_Utf81
CONSTANT_MethodHandle15
CONSTANT_MethodType16
CONSTANT_InvokeDynamic18

以下分别给出CONSTANT_Class、CONSTANT_Methodref、CONSTANT_Fieldref、CONSTANT_String、CONSTANT_Utf8、CONSTANT_NameAndType的结构。

CONSTANT_Class

CONSTANT_Class_info {
    u1 tag;
    u2 name_index;
}

CONSTANT_Methodref

CONSTANT_Methodref_info {
    u1 tag;
    u2 class_index;
    u2 name_and_type_index;
}

CONSTANT_Fieldref

CONSTANT_Fieldref_info {
    u1 tag;
    u2 class_index;
    u2 name_and_type_index;
}

CONSTANT_String

CONSTANT_String_info {
    u1 tag;
    u2 string_index;
}

CONSTANT_Utf8

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}

CONSTANT_NameAndType

CONSTANT_NameAndType_info {
    u1 tag;
    u2 name_index;
    u2 descriptor_index;
}
#1 = Methodref #6.#20 //这是第一项,引用第6项和第20项常量,值为:java/lang/Object."<init>": ()V

tag为0a=10,为CONSTANT_Methodref,取5个字节:0a 00 06 00 14

  • ca fe ba be 00 00 00 34 00 22 0a 00 06 00 14 09
  • 00 15 00 16 08 00 17 0a 00 18 00 19 07 00 1a 07
CONSTANT_Methodref_info {
    u1 tag; 0a = 10 => CONSTANT_Methodref
    u2 class_index; 00 06 = 6 => 引用第6项常量
    u2 name_and_type_index; 00 14 = 20 => 引用第20项常量
}
#2 = Fieldref #21.#22 // java/lang/System.out:Ljava/io/PrintStream;

tag为09=9,为CONSTANT_Fieldref,取5个字节:09 00 15 00 16

  • ca fe ba be 00 00 00 34 00 22 0a 00 06 00 14 09
  • 00 15 00 16 08 00 17 0a 00 18 00 19 07 00 1a 07
CONSTANT_Fieldref_info {
    u1 tag;  09 = 9 => CONSTANT_Fieldref
    u2 class_index; 00 15 = 21 => 引用第21项常量
    u2 name_and_type_index; 00 16 = 22 => 引用第22项常量
}
#3 = String #23 // Hello world
  • ca fe ba be 00 00 00 34 00 22 0a 00 06 00 14 09
  • 00 15 00 16 08 00 17 0a 00 18 00 19 07 00 1a 07
CONSTANT_String_info {
    u1 tag; 08 = 8 => CONSTANT_String
    u2 string_index; 00 17 = 23 => 引用第23项常量
}
#4 = Methodref #24.#25 // java/io/PrintStream.println:(Ljava/lang/String;)V
  • ca fe ba be 00 00 00 34 00 22 0a 00 06 00 14 09
  • 00 15 00 16 08 00 17 0a 00 18 00 19 07 00 1a 07
CONSTANT_Methodref_info {
    u1 tag; 0a = 10 => CONSTANT_Methodref
    u2 class_index; 00 18 = 24 => 引用第24项常量
    u2 name_and_type_index; 00 19 = 25 => 引用第25项常量
}
#5 = Class #26 // Test
  • ca fe ba be 00 00 00 34 00 22 0a 00 06 00 14 09
  • 00 15 00 16 08 00 17 0a 00 18 00 19 07 00 1a 07
CONSTANT_Class_info {
    u1 tag; 07 = 7 => CONSTANT_Class
    u2 name_index; 00 1a = 26 => 引用第26项常量
}
#6 = Class #27 // java/lang/Object
  • 1 ca fe ba be 00 00 00 34 00 22 0a 00 06 00 14 09
  • 2 00 15 00 16 08 00 17 0a 00 18 00 19 07 00 1a 07
  • 3 00 1b 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29
CONSTANT_Class_info {
    u1 tag; 07 = 7 => CONSTANT_Class
    u2 name_index; 00 1b = 27 => 引用第27项常量
}
#7 = Utf8 <init>
  • 1 ca fe ba be 00 00 00 34 00 22 0a 00 06 00 14 09
  • 2 00 15 00 16 08 00 17 0a 00 18 00 19 07 00 1a 07
  • 3 00 1b 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29
CONSTANT_Utf8_info {
    u1 tag; 01 = 1 => CONSTANT_Utf8
    u2 length; 00 06 = 6 => 后续跟6个字节长度的字符
    u1 bytes[length]; 3c 69 6e 69 74 3e => <init>
}

unicode字符:
3c 69 6e 69 74 3e

#8 = Utf8 ()V
  • 2 00 15 00 16 08 00 17 0a 00 18 00 19 07 00 1a 07
  • 3 00 1b 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29
  • 4 56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e
CONSTANT_Utf8_info {
    u1 tag; 01 = 1 => CONSTANT_Utf8
    u2 length; 00 03 = 3 => 后续跟3个字节长度的字符
    u1 bytes[length]; 28 29 56 => ()V
}

unicode字符:
28 29 56

#9 = Utf8 Code
  • 2 00 15 00 16 08 00 17 0a 00 18 00 19 07 00 1a 07
  • 3 00 1b 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29
  • 4 56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e
CONSTANT_Utf8_info {
    u1 tag; 01 = 1 => CONSTANT_Utf8
    u2 length; 00 04 = 4 => 后续跟4个字节长度的字符
    u1 bytes[length]; 43 6f 64 65 => Code
}

unicode字符:
43 6f 64 65

#10 = Utf8 LineNumberTable
  • 3 00 1b 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29
  • 4 56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e
  • 5 75 6d 62 65 72 54 61 62 6c 65 01 00 12 4c 6f 63
CONSTANT_Utf8_info {
    u1 tag; 01 = 1 => CONSTANT_Utf8
    u2 length; 00 0f = 15 => 后续跟15个字节长度的字符
    u1 bytes[length]; 4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c 65=> LineNumberTable
}

unicode字符:
4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c 65

#11 = Utf8 LocalVariableTable
  • 3 00 1b 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29
  • 4 56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e
  • 5 75 6d 62 65 72 54 61 62 6c 65 01 00 12 4c 6f 63
  • 6 61 6c 56 61 72 69 61 62 6c 65 54 61 62 6c 65 01
CONSTANT_Utf8_info {
    u1 tag; 01 = 1 => CONSTANT_Utf8
    u2 length; 00 12 = 18 => 后续跟18个字节长度的字符
    u1 bytes[length]; 4c 6f 63 61 6c 56 61 72 69 61 62 6c 65 54 61 62 6c 65 => LocalVariableTable
}

unicode字符:
4c 6f 63 61 6c 56 61 72 69 61 62 6c 65 54 61 62 6c 65

#12 = Utf8 this
  • 4 56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e
  • 5 75 6d 62 65 72 54 61 62 6c 65 01 00 12 4c 6f 63
  • 6 61 6c 56 61 72 69 61 62 6c 65 54 61 62 6c 65 01
  • 7 00 04 74 68 69 73 01 00 06 4c 54 65 73 74 3b 01
CONSTANT_Utf8_info {
    u1 tag; 01 = 1 => CONSTANT_Utf8
    u2 length; 00 04 = 4 => 后续跟4个字节长度的字符
    u1 bytes[length]; 74 68 69 73 => this
}

unicode字符:
74 68 69 73

#13 = Utf8 LTest;
  • 4 56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e
  • 5 75 6d 62 65 72 54 61 62 6c 65 01 00 12 4c 6f 63
  • 6 61 6c 56 61 72 69 61 62 6c 65 54 61 62 6c 65 01
  • 7 00 04 74 68 69 73 01 00 06 4c 54 65 73 74 3b 01
CONSTANT_Utf8_info {
    u1 tag; 01 = 1 => CONSTANT_Utf8
    u2 length; 00 06 = 6 => 后续跟6个字节长度的字符
    u1 bytes[length]; 4c 54 65 73 74 3b => LTest;
}

unicode字符:
4c 54 65 73 74 3b

#14 = Utf8 main
  • 5 75 6d 62 65 72 54 61 62 6c 65 01 00 12 4c 6f 63
  • 6 61 6c 56 61 72 69 61 62 6c 65 54 61 62 6c 65 01
  • 7 00 04 74 68 69 73 01 00 06 4c 54 65 73 74 3b 01
  • 8 00 04 6d 61 69 6e 01 00 16 28 5b 4c 6a 61 76 61
CONSTANT_Utf8_info {
    u1 tag; 01 = 1 => CONSTANT_Utf8
    u2 length; 00 04 = 4 => 后续跟4个字节长度的字符
    u1 bytes[length]; 6d 61 69 6e => main
}

unicode字符:
6d 61 69 6e

#15 = Utf8 ([Ljava/lang/String;)V
  • 6 61 6c 56 61 72 69 61 62 6c 65 54 61 62 6c 65 01
  • 7 00 04 74 68 69 73 01 00 06 4c 54 65 73 74 3b 01
  • 8 00 04 6d 61 69 6e 01 00 16 28 5b 4c 6a 61 76 61
  • 9 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 29 56 01
CONSTANT_Utf8_info {
    u1 tag; 01 = 1 => CONSTANT_Utf8
    u2 length; 00 16 = 22 => 后续跟22个字节长度的字符
    u1 bytes[length]; 28 5b 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 29 56 => ([Ljava/lang/String;)V
}

unicode字符:
28 5b 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 29 56

#16 = Utf8 args
  • 07 00 04 74 68 69 73 01 00 06 4c 54 65 73 74 3b 01
  • 08 00 04 6d 61 69 6e 01 00 16 28 5b 4c 6a 61 76 61
  • 09 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 29 56 01
  • 10 00 04 61 72 67 73 01 00 13 5b 4c 6a 61 76 61 2f
CONSTANT_Utf8_info {
    u1 tag; 01 = 1 => CONSTANT_Utf8
    u2 length; 00 04 = 4 => 后续跟4个字节长度的字符
    u1 bytes[length]; 61 72 67 73 => args
}

unicode字符:
61 72 67 73

#17 = Utf8 [Ljava/lang/String;
  • 08 00 04 6d 61 69 6e 01 00 16 28 5b 4c 6a 61 76 61
  • 09 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 29 56 01
  • 10 00 04 61 72 67 73 01 00 13 5b 4c 6a 61 76 61 2f
  • 11 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 01 00 0a 53
CONSTANT_Utf8_info {
    u1 tag; 01 = 1 => CONSTANT_Utf8
    u2 length; 00 13 = 19 => 后续跟19个字节长度的字符
    u1 bytes[length]; 5b 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b => [Ljava/lang/String;
}

unicode字符:
5b 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b

#18 = Utf8 SourceFile
  • 09 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 29 56 01
  • 10 00 04 61 72 67 73 01 00 13 5b 4c 6a 61 76 61 2f
  • 11 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 01 00 0a 53
  • 12 6f 75 72 63 65 46 69 6c 65 01 00 09 54 65 73 74
CONSTANT_Utf8_info {
    u1 tag; 01 = 1 => CONSTANT_Utf8
    u2 length; 00 0a = 10 => 后续跟10个字节长度的字符
    u1 bytes[length]; 53 6f 75 72 63 65 46 69 6c 65 => SourceFile
}

unicode字符:
53 6f 75 72 63 65 46 69 6c 65

#19 = Utf8 Test.java
  • 10 00 04 61 72 67 73 01 00 13 5b 4c 6a 61 76 61 2f
  • 11 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 01 00 0a 53
  • 12 6f 75 72 63 65 46 69 6c 65 01 00 09 54 65 73 74
  • 13 2e 6a 61 76 61 0c 00 07 00 08 07 00 1c 0c 00 1d
CONSTANT_Utf8_info {
    u1 tag; 01 = 1 => CONSTANT_Utf8
    u2 length; 00 09 = 9 => 后续跟9个字节长度的字符
    u1 bytes[length]; 54 65 73 74 2e 6a 61 76 61 => Test.java
}

unicode字符:
54 65 73 74 2e 6a 61 76 61

#20 = NameAndType #7:#8 // “<init>”: ()V
  • 10 00 04 61 72 67 73 01 00 13 5b 4c 6a 61 76 61 2f
  • 11 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 01 00 0a 53
  • 12 6f 75 72 63 65 46 69 6c 65 01 00 09 54 65 73 74
  • 13 2e 6a 61 76 61 0c 00 07 00 08 07 00 1c 0c 00 1d
CONSTANT_NameAndType_info {
    u1 tag; 0c = 12 => CONSTANT_NameAndType
    u2 name_index; 00 07 = 7 => 引用第7项常量
    u2 descriptor_index; 00 08 = 8 => 引用第8项常量
}
#21 = Class #28 // java/lang/System
  • 10 00 04 61 72 67 73 01 00 13 5b 4c 6a 61 76 61 2f
  • 11 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 01 00 0a 53
  • 12 6f 75 72 63 65 46 69 6c 65 01 00 09 54 65 73 74
  • 13 2e 6a 61 76 61 0c 00 07 00 08 07 00 1c 0c 00 1d
CONSTANT_Class_info {
    u1 tag; 07 = 7 => CONSTANT_Class
    u2 name_index; 00 1c = 28 => 引用第28项常量
}
#22 = NameAndType #29:#30 // out:Ljava/io/PrintStream;
  • 11 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 01 00 0a 53
  • 12 6f 75 72 63 65 46 69 6c 65 01 00 09 54 65 73 74
  • 13 2e 6a 61 76 61 0c 00 07 00 08 07 00 1c 0c 00 1d
  • 14 00 1e 01 00 0b 48 65 6c 6c 6f 20 77 6f 72 6c 64
CONSTANT_NameAndType_info {
    u1 tag; 0c = 12 => CONSTANT_NameAndType
    u2 name_index; 00 1d = 29 => 引用第29项常量
    u2 descriptor_index; 00 1e = 30 => 引用第30项常量
}
#23 = Utf8 Hello world
  • 11 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 01 00 0a 53
  • 12 6f 75 72 63 65 46 69 6c 65 01 00 09 54 65 73 74
  • 13 2e 6a 61 76 61 0c 00 07 00 08 07 00 1c 0c 00 1d
  • 14 00 1e 01 00 0b 48 65 6c 6c 6f 20 77 6f 72 6c 64
CONSTANT_Utf8_info {
    u1 tag; 01 = 1 => CONSTANT_Utf8
    u2 length; 00 0b = 11 => 后续跟11个字节长度的字符
    u1 bytes[length]; 48 65 6c 6c 6f 20 77 6f 72 6c 64 => Hello world
}

unicode字符:
48 65 6c 6c 6f 20 77 6f 72 6c 64

#24 = Class #31 // java/io/PrintStream
  • 12 6f 75 72 63 65 46 69 6c 65 01 00 09 54 65 73 74
  • 13 2e 6a 61 76 61 0c 00 07 00 08 07 00 1c 0c 00 1d
  • 14 00 1e 01 00 0b 48 65 6c 6c 6f 20 77 6f 72 6c 64
  • 15 07 00 1f 0c 00 20 00 21 01 00 04 54 65 73 74 01
CONSTANT_Class_info {
    u1 tag; 07 = 7 => CONSTANT_Class
    u2 name_index; 00 1f = 31 => 引用第31项常量
}
#25 = NameAndType #32:#33 // println:(Ljava/lang/String;)V
  • 12 6f 75 72 63 65 46 69 6c 65 01 00 09 54 65 73 74
  • 13 2e 6a 61 76 61 0c 00 07 00 08 07 00 1c 0c 00 1d
  • 14 00 1e 01 00 0b 48 65 6c 6c 6f 20 77 6f 72 6c 64
  • 15 07 00 1f 0c 00 20 00 21 01 00 04 54 65 73 74 01
CONSTANT_NameAndType_info {
    u1 tag; 0c = 12 => CONSTANT_NameAndType
    u2 name_index; 00 20 = 32 => 引用第32项常量
    u2 descriptor_index; 00 21 = 33 => 引用第33项常量
}
#26 = Utf8 Test
  • 12 6f 75 72 63 65 46 69 6c 65 01 00 09 54 65 73 74
  • 13 2e 6a 61 76 61 0c 00 07 00 08 07 00 1c 0c 00 1d
  • 14 00 1e 01 00 0b 48 65 6c 6c 6f 20 77 6f 72 6c 64
  • 15 07 00 1f 0c 00 20 00 21 01 00 04 54 65 73 74 01
CONSTANT_Utf8_info {
    u1 tag; 01 = 1 => CONSTANT_Utf8
    u2 length; 00 04 = 4 => 后续跟4个字节长度的字符
    u1 bytes[length]; 54 65 73 74 => Test
}

unicode字符:
54 65 73 74

#27 = Utf8 java/lang/Object
  • 13 2e 6a 61 76 61 0c 00 07 00 08 07 00 1c 0c 00 1d
  • 14 00 1e 01 00 0b 48 65 6c 6c 6f 20 77 6f 72 6c 64
  • 15 07 00 1f 0c 00 20 00 21 01 00 04 54 65 73 74 01
  • 16 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65
  • 17 63 74 01 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 53
CONSTANT_Utf8_info {
    u1 tag; 01 = 1 => CONSTANT_Utf8
    u2 length; 00 10 = 16 => 后续跟16个字节长度的字符
    u1 bytes[length]; 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 => java/lang/Object
}

unicode字符:
6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74

#28 = Utf8 java/lang/System
  • 14 00 1e 01 00 0b 48 65 6c 6c 6f 20 77 6f 72 6c 64
  • 15 07 00 1f 0c 00 20 00 21 01 00 04 54 65 73 74 01
  • 16 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65
  • 17 63 74 01 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 53
  • 18 79 73 74 65 6d 01 00 03 6f 75 74 01 00 15 4c 6a
CONSTANT_Utf8_info {
    u1 tag; 01 = 1 => CONSTANT_Utf8
    u2 length; 00 10 = 16 => 后续跟16个字节长度的字符
    u1 bytes[length]; 6a 61 76 61 2f 6c 61 6e 67 2f 53 79 73 74 65 6d => java/lang/System
}

unicode字符:
6a 61 76 61 2f 6c 61 6e 67 2f 53 79 73 74 65 6d

#29 = Utf8 out
  • 15 07 00 1f 0c 00 20 00 21 01 00 04 54 65 73 74 01
  • 16 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65
  • 17 63 74 01 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 53
  • 18 79 73 74 65 6d 01 00 03 6f 75 74 01 00 15 4c 6a
CONSTANT_Utf8_info {
    u1 tag; 01 = 1 => CONSTANT_Utf8
    u2 length; 00 03 = 3 => 后续跟3个字节长度的字符
    u1 bytes[length]; 6f 75 74 => out
}

unicode字符:
6f 75 74

#30 = Utf8 Ljava/io/PrintStream;
  • 16 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65
  • 17 63 74 01 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 53
  • 18 79 73 74 65 6d 01 00 03 6f 75 74 01 00 15 4c 6a
  • 19 61 76 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72 65
  • 20 61 6d 3b 01 00 13 6a 61 76 61 2f 69 6f 2f 50 72
CONSTANT_Utf8_info {
    u1 tag; 01 = 1 => CONSTANT_Utf8
    u2 length; 00 15 = 21 => 后续跟21个字节长度的字符
    u1 bytes[length]; 4c 6a 61 76 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72 65 61 6d 3b => Ljava/io/PrintStream;
}

unicode字符:
4c 6a 61 76 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72 65 61 6d 3b

#31 = Utf8 java/io/PrintStream
  • 17 63 74 01 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 53
  • 18 79 73 74 65 6d 01 00 03 6f 75 74 01 00 15 4c 6a
  • 19 61 76 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72 65
  • 20 61 6d 3b 01 00 13 6a 61 76 61 2f 69 6f 2f 50 72
  • 21 69 6e 74 53 74 72 65 61 6d 01 00 07 70 72 69 6e
CONSTANT_Utf8_info {
    u1 tag; 01 = 1 => CONSTANT_Utf8
    u2 length; 00 13 = 19 => 后续跟19个字节长度的字符
    u1 bytes[length]; 6a 61 76 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72 65 61 6d => java/io/PrintStream
}

unicode字符:
6a 61 76 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72 65 61 6d

#32 = Utf8 println
  • 18 79 73 74 65 6d 01 00 03 6f 75 74 01 00 15 4c 6a
  • 19 61 76 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72 65
  • 20 61 6d 3b 01 00 13 6a 61 76 61 2f 69 6f 2f 50 72
  • 21 69 6e 74 53 74 72 65 61 6d 01 00 07 70 72 69 6e
  • 22 74 6c 6e 01 00 15 28 4c 6a 61 76 61 2f 6c 61 6e
CONSTANT_Utf8_info {
    u1 tag; 01 = 1 => CONSTANT_Utf8
    u2 length; 00 07 = 7 => 后续跟7个字节长度的字符
    u1 bytes[length]; 70 72 69 6e 74 6c 6e => println
}

unicode字符:
70 72 69 6e 74 6c 6e

#33 = Utf8 (Ljava/lang/String;)V
  • 19 61 76 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72 65
  • 20 61 6d 3b 01 00 13 6a 61 76 61 2f 69 6f 2f 50 72
  • 21 69 6e 74 53 74 72 65 61 6d 01 00 07 70 72 69 6e
  • 22 74 6c 6e 01 00 15 28 4c 6a 61 76 61 2f 6c 61 6e
  • 23 67 2f 53 74 72 69 6e 67 3b 29 56 00 21 00 05 00
CONSTANT_Utf8_info {
    u1 tag; 01 = 1 => CONSTANT_Utf8
    u2 length; 00 15 = 21 => 后续跟21个字节长度的字符
    u1 bytes[length]; 28 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 29 56 => (Ljava/lang/String;)V
}

unicode字符:
28 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 29 56

常量表到此结束。

u2 access_flags;

flags: ACC_PUBLIC, ACC_SUPER

access_flags 项的值是一个标志掩码,用于表示对此类或接口的访问权限和属性。

Flag Nametag值解释
ACC_PUBLIC0x0001公开; 可以从其包外部访问。
ACC_FINAL0x0010声明为最终; 不允许子类。
ACC_SUPER0x0020当被 invokespecial 指令调用时,特别对待超类方法。
ACC_INTERFACE0x0200是接口,不是类。
ACC_ABSTRACT0x0400声明为抽象类; 不得实例化。
ACC_SYNTHETIC0x1000声明合成; 源代码中不存在。
ACC_ANNOTATION0x2000声明为注释类型。
ACC_ENUM0x4000声明为枚举类型。
access_flags=0021=0x0001+0x0020=ACC_PUBLIC, ACC_SUPER
  • 20 61 6d 3b 01 00 13 6a 61 76 61 2f 69 6f 2f 50 72
  • 21 69 6e 74 53 74 72 65 61 6d 01 00 07 70 72 69 6e
  • 22 74 6c 6e 01 00 15 28 4c 6a 61 76 61 2f 6c 61 6e
  • 23 67 2f 53 74 72 69 6e 67 3b 29 56 00 21 00 05 00

u2 this_class;

class: Test
this_class=0005=5 =>指向常量表第5项: #5 = Class #26 // Test
  • 21 69 6e 74 53 74 72 65 61 6d 01 00 07 70 72 69 6e
  • 22 74 6c 6e 01 00 15 28 4c 6a 61 76 61 2f 6c 61 6e
  • 23 67 2f 53 74 72 69 6e 67 3b 29 56 00 21 00 05 00

u2 super_class;

super class: java/lang/Object
super_class=0006=6 =>指向常量表第6项: #6 = Class #27 // java/lang/Object
  • 22 74 6c 6e 01 00 15 28 4c 6a 61 76 61 2f 6c 61 6e
  • 23 67 2f 53 74 72 69 6e 67 3b 29 56 00 21 00 05 00
  • 24 06 00 00 00 00 00 02 00 01 00 07 00 08 00 01 00

u2 interfaces_count;

interfaces_count: 0
interfaces_count=0000=0
  • 22 74 6c 6e 01 00 15 28 4c 6a 61 76 61 2f 6c 61 6e
  • 23 67 2f 53 74 72 69 6e 67 3b 29 56 00 21 00 05 00
  • 24 06 00 00 00 00 00 02 00 01 00 07 00 08 00 01 00

u2 interfaces[interfaces_count];

interfaces_count为0,该项为空,不占用字节。

u2 fields_count;

fields_count: 0
fields_count=0000=0
  • 22 74 6c 6e 01 00 15 28 4c 6a 61 76 61 2f 6c 61 6e
  • 23 67 2f 53 74 72 69 6e 67 3b 29 56 00 21 00 05 00
  • 24 06 00 00 00 00 00 02 00 01 00 07 00 08 00 01 00

field_info fields[fields_count];

fields_count为0,该项为空,不占用字节。

u2 methods_count;

methods_count: 2,有两个方法。
methods_count=0002=2
  • 22 74 6c 6e 01 00 15 28 4c 6a 61 76 61 2f 6c 61 6e
  • 23 67 2f 53 74 72 69 6e 67 3b 29 56 00 21 00 05 00
  • 24 06 00 00 00 00 00 02 00 01 00 07 00 08 00 01 00

method_info methods[methods_count];

method结构如下:
method_info

method_info {
    u2             access_flags;
    u2             name_index;
    u2             descriptor_index;
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

access_flags:Method访问和属性标志

Flag Nametag值解释
ACC_PUBLIC0x0001公开; 可以从其包外部访问。
ACC_PRIVATE0x0002声明为私有; 只能在定义类中访问。
ACC_PROTECTED0x0004声明受保护; 可以在子类中访问。
ACC_STATIC0x0008声明为静态。
ACC_FINAL0x0010声明为最终; 不得被覆盖。
ACC_SYNCHRONIZED0x0020声明同步; 调用由监视器使用包装。
ACC_BRIDGE0x0040由编译器生成的桥接方法。
ACC_VARARGS0x0080用可变数量的参数声明。
ACC_NATIVE0x0100声明为本地; 用 Java 以外的语言实现。
ACC_ABSTRACT0x0400声明为抽象类; 没有提供实现。
ACC_STRICT0x0800声明的strictfp; 浮点模式是 FP-strict。
ACC_SYNTHETIC0x1000声明合成; 源代码中不存在。
#method1: public Test();
  • flags: ACC_PUBLIC
  • name: <init>
  • descriptor: ()V
  • attributes_count: 1
  • 22 74 6c 6e 01 00 15 28 4c 6a 61 76 61 2f 6c 61 6e
  • 23 67 2f 53 74 72 69 6e 67 3b 29 56 00 21 00 05 00
  • 24 06 00 00 00 00 00 02 00 01 00 07 00 08 00 01 00
method_info {
    u2             access_flags; 00 01 => ACC_PUBLIC
    u2             name_index; 00 07 = 7 => #7 = Utf8 <init>
    u2             descriptor_index; 00 08 = 8 => #8 = Utf8 ()V
    u2             attributes_count; 00 01 = 1
    attribute_info attributes[attributes_count];
}
attributes说明

attributes: 共23种类型的attribute
attributes通用格式如下:
attribute_info

attribute_info {
    u2 attribute_name_index; //常量表序号,attribute的名称
    u4 attribute_length;//attribute占用的字节长度,不包括attribute_name_index和attribute_length占用的6个字节
    u1 info[attribute_length];//字节数组
}
#method1

attribute name: Code
attribute 长度: 47字节

  • 23 67 2f 53 74 72 69 6e 67 3b 29 56 00 21 00 05 00
  • 24 06 00 00 00 00 00 02 00 01 00 07 00 08 00 01 00
  • 25 09 00 00 00 2f 00 01 00 01 00 00 00 05 2a b7 00
attribute_info {
    u2 attribute_name_index; 00 09 = 9 => #9 = Utf8 Code
    u4 attribute_length; 00 00 00 2f = 47
    u1 info[attribute_length];
}
Code attribute说明

Code attribute格式如下:
Code_attribute

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];
}
指令集说明

Instruction Set

#method1 前两个字节指示的是code,因此attribute_info需要转成具体的Code_attribute
  • Code attribute name: Code
  • Code attribute 长度: 47字节
  • stack=1, locals=1
  • 0: aload_0
  • 1: invokespecial #1
  • 4: return
  • LineNumberTable: line 1: 0
  • LocalVariableTable: Start:0 Length:5 Slot:0 Name:this Signature:LTest;
  • 24 06 00 00 00 00 00 02 00 01 00 07 00 08 00 01 00
  • 25 09 00 00 00 2f 00 01 00 01 00 00 00 05 2a b7 00
  • 26 01 b1 00 00 00 02 00 0a 00 00 00 06 00 01 00 00
  • 27 00 01 00 0b 00 00 00 0c 00 01 00 00 00 05 00 0c
  • 28 00 0d 00 00 00 09 00 0e 00 0f 00 01 00 09 00 00
Code_attribute {
    u2 attribute_name_index; 00 09 = 9 => #9 = Utf8 Code
    u4 attribute_length; 00 00 00 2f = 47
    u2 max_stack; 00 01 = 1 => stack=1
    u2 max_locals; 00 01 = 1 => locals=1
    u4 code_length; 00 00 00 05 = 5 => 后续5个字节为命令区
    u1 code[code_length]; 2a : b7 00 01 : b1 按照指令集格式解析成3个指令 aload_0、 invokespecial #1 和 return
         2a = 42 => aload_0 = 42 (0x2a) this指针入操作数栈 
         b7 00 01 => (invokespecial indexbyte1 indexbyte2) 调用默认构造函数
             b7 = 183 => invokespecial = 183 (0xb7)
             00 01 => #1 = Methodref          #6.#20         // java/lang/Object."<init>":()V 
         b1 = 177 => return = 177 (0xb1)  返回,退出操作数栈 
    u2 exception_table_length; 00 00 = 0 无异常表
    {   u2 start_pc;
        u2 end_pc;
        u2 handler_pc;
        u2 catch_type;
    } exception_table[exception_table_length];
    u2 attributes_count; 00 02 = 2 两个属性,后续字节包含两个attribute
    attribute_info attributes[attributes_count]; attributes[2]解析得LineNumberTable和LocalVariableTable两个属性
			LineNumberTable_attribute {
				u2 attribute_name_index; 00 0a = 10 => #10 = Utf8               LineNumberTable
				u4 attribute_length; 00 00 00 06 = 6
				u2 line_number_table_length; 00 01 = 1
				{   u2 start_pc; 00 00 = 0
					u2 line_number;	00 01 = 1
				} line_number_table[line_number_table_length];
			}	
			LocalVariableTable_attribute {
				u2 attribute_name_index;00 0b = 11 => #11 = Utf8               LocalVariableTable
				u4 attribute_length; 00 00 00 0c = 12
				u2 local_variable_table_length; 00 01 = 1
				{   u2 start_pc; 00 00 = 0
					u2 length; 00 05 = 5 //参考前面5个字节的命令区
					u2 name_index; 00 0c = 12 => #12 = Utf8               this
					u2 descriptor_index; 00 0d = 13 => #13 = Utf8               LTest;
					u2 index; 00 00 = 0
				} local_variable_table[local_variable_table_length];
			}
}

对应如下代码:

   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 // 指令aload_0对应于第一行源代码
     LocalVariableTable:
       Start  Length  Slot  Name   Signature
           0       5     0  this   LTest;
#method2: public static void main(java.lang.String[]);
  • flags: ACC_PUBLIC, ACC_STATIC
  • name: main
  • descriptor: ([Ljava/lang/String;)V
  • attributes_count: 1
  • 24 06 00 00 00 00 00 02 00 01 00 07 00 08 00 01 00
  • 25 09 00 00 00 2f 00 01 00 01 00 00 00 05 2a b7 00
  • 26 01 b1 00 00 00 02 00 0a 00 00 00 06 00 01 00 00
  • 27 00 01 00 0b 00 00 00 0c 00 01 00 00 00 05 00 0c
  • 28 00 0d 00 00 00 09 00 0e 00 0f 00 01 00 09 00 00
method_info {
    u2             access_flags; 00 09 = 0x0001 + 0x0008 => ACC_PUBLIC + ACC_STATIC
    u2             name_index; 00 0e = 14 => #14 = Utf8               main
    u2             descriptor_index; 00 0f = 15 => #15 = Utf8               ([Ljava/lang/String;)V
    u2             attributes_count; 00 01 = 1
    attribute_info attributes[attributes_count];
}
#method2
  • Code attribute name: Code
  • Code attribute 长度: 55字节
  • stack=2, locals=1
  • 0: getstatic #2
  • 3: ldc #3
  • 5: invokevirtual #4
  • 4: return
  • LineNumberTable: line 3: 0 line 4: 8
  • LocalVariableTable: Start:0 Length:9 Slot:0 Name:args Signature:[Ljava/lang/String;
  • 27 00 01 00 0b 00 00 00 0c 00 01 00 00 00 05 00 0c
  • 28 00 0d 00 00 00 09 00 0e 00 0f 00 01 00 09 00 00
  • 29 00 37 00 02 00 01 00 00 00 09 b2 00 02 12 03 b6
  • 30 00 04 b1 00 00 00 02 00 0a 00 00 00 0a 00 02 00
  • 31 00 00 03 00 08 00 04 00 0b 00 00 00 0c 00 01 00
  • 32 00 00 09 00 10 00 11 00 00 00 01 00 12 00 00 00
  • 33 02 00 13
Code_attribute {
    u2 attribute_name_index; 00 09 = 9 => #9 = Utf8 Code
    u4 attribute_length; 00 00 00 37 = 55
    u2 max_stack; 00 02 = 2 => stack=2
    u2 max_locals; 00 01 = 1 => locals=1
    u4 code_length; 00 00 00 09 = 9 => 后续9个字节为命令区
    u1 code[code_length]; b2 00 02: 12 03: b6 00 04: b1  按照指令集格式解析成4个指令getstatic #2、ldc #3、invokevirtual #4 和 return
         b2 00 02 => (getstatic  indexbyte1 indexbyt2) getstatic = 178 (0xb2) #2 = Fieldref #21.#22 // java/lang/System.out:Ljava/io/PrintStream;
         12 03 => (ldc index) ldc = 18 (0x12) #3 = String             #23            // Hello world
         b6 00 04 => (invokevirtual indexbyte1 indexbyt2) invokevirtual = 182 (0xb6) #4 = Methodref          #24.#25        // java/io/PrintStream.println:(Ljava/lang/String;)V
         b1 = 177 => return = 177 (0xb1)  返回,退出操作数栈 
    u2 exception_table_length; 00 00 = 0 无异常表
    {   u2 start_pc;
        u2 end_pc;
        u2 handler_pc;
        u2 catch_type;
    } exception_table[exception_table_length];
    u2 attributes_count; 00 02 = 2 两个属性,后续字节包含两个attribute
    attribute_info attributes[attributes_count]; attributes[2]解析得LineNumberTable和LocalVariableTable两个属性
			LineNumberTable_attribute {
				u2 attribute_name_index; 00 0a = 10 => #10 = Utf8               LineNumberTable
				u4 attribute_length; 00 00 00 0a = 10
				u2 line_number_table_length; 00 02 = 2
				{   u2 start_pc; 00 00 = 0
					u2 line_number;	00 03 = 3
				} line_number_table[line_number_table_length]; // line 3: 0
				{   u2 start_pc; 00 08 = 8
					u2 line_number;	00 04 = 4
				} line_number_table[line_number_table_length]; // line 4: 8
			}	
			LocalVariableTable_attribute {
				u2 attribute_name_index;00 0b = 11 => #11 = Utf8               LocalVariableTable
				u4 attribute_length; 00 00 00 0c = 12
				u2 local_variable_table_length; 00 01 = 1
				{   u2 start_pc; 00 00 = 0
					u2 length; 00 09 = 9  //参考前面9个字节的命令区
					u2 name_index;  00 10 = 16 => #16 = Utf8               args
					u2 descriptor_index; 00 11 = 17 => #17 = Utf8               [Ljava/lang/String;
					u2 index; 00 00 = 0
				} local_variable_table[local_variable_table_length];
			}
}

对应如下代码:

   Code:
     stack=2, locals=1, args_size=1
        0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        3: ldc           #3                  // String Hello world
        5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        8: return
     LineNumberTable:
       line 3: 0 // 指令getstatic对应于第3行源代码
       line 4: 8 // 指令return对应于第4行源代码
     LocalVariableTable:
       Start  Length  Slot  Name   Signature
           0       9     0  args   [Ljava/lang/String;

u2 attributes_count;

占2字节,0001 attributes_count = 1

  • 31 00 00 03 00 08 00 04 00 0b 00 00 00 0c 00 01 00
  • 32 00 00 09 00 10 00 11 00 00 00 01 00 12 00 00 00
  • 33 02 00 13

attribute_info attributes[attributes_count];

SourceFile: “Test.java”

attribute_name=SourceFile,启用 SourceFile_attribute 格式解析

  • 31 00 00 03 00 08 00 04 00 0b 00 00 00 0c 00 01 00
  • 32 00 00 09 00 10 00 11 00 00 00 01 00 12 00 00 00
  • 33 02 00 13
   attribute_info attributes[attributes_count];
		SourceFile_attribute {
			u2 attribute_name_index; 00 12 = 18 => #18 = Utf8               SourceFile
			u4 attribute_length; 00 00 00 02 = 2
			u2 sourcefile_index; 00 13 = 19 => #19 = Utf8               Test.java
		}

END

javap -v 结果

public class Test
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#20         // java/lang/Object."<init>":()V
   #2 = Fieldref           #21.#22        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = String             #23            // Hello world
   #4 = Methodref          #24.#25        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #5 = Class              #26            // Test
   #6 = Class              #27            // java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               LTest;
  #14 = Utf8               main
  #15 = Utf8               ([Ljava/lang/String;)V
  #16 = Utf8               args
  #17 = Utf8               [Ljava/lang/String;
  #18 = Utf8               SourceFile
  #19 = Utf8               Test.java
  #20 = NameAndType        #7:#8          // "<init>":()V
  #21 = Class              #28            // java/lang/System
  #22 = NameAndType        #29:#30        // out:Ljava/io/PrintStream;
  #23 = Utf8               Hello world
  #24 = Class              #31            // java/io/PrintStream
  #25 = NameAndType        #32:#33        // println:(Ljava/lang/String;)V
  #26 = Utf8               Test
  #27 = Utf8               java/lang/Object
  #28 = Utf8               java/lang/System
  #29 = Utf8               out
  #30 = Utf8               Ljava/io/PrintStream;
  #31 = Utf8               java/io/PrintStream
  #32 = Utf8               println
  #33 = Utf8               (Ljava/lang/String;)V
{
  public Test();
    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
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   LTest;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String Hello world
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 3: 0
        line 4: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  args   [Ljava/lang/String;
}
SourceFile: "Test.java"
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值