Java虚拟机学习---Class文件解析

class文件整体结构: 

类型名称   说明长度
u4magic魔数,识别Class文件格式4个字节
u2            minor_version副版本号2个字节
u2         major_version 主版本号 2个字节
u2           constant_pool_count常量池计算器 2个字节
cp_info            constant_pool常量池n个字节
u2            access_flags访问标志2个字节
u2            this_class类索引2个字节
u2            super_class父类索引2个字节
u2          interfaces_count接口计数器 2个字节
u2           interfaces接口索引集合 2个字节
u2            fields_count字段个数2个字节
field_info         fields字段集合n个字节
u2           methods_count方法计数器 2个字节
method_info   methods方法集合n个字节
u2            attributes_count附加属性计数器2个字节
attribute_info  attributes附加属性集合  n个字节

   表中的u1、u2、u4、u8来分别代表1个字节、2个字节、4个字节和8个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者按照UTF-8编码构成的字符串值。

Person类声明如下:

package build;

public class Person {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "name:"+name+",age:"+age;
    }
}

Main类的声明如下:

package build;

public class Main {

    public static String TAG = "This is a tag";
    public static int mType = 1234;

    public static void main(String[] params) {
        Person person = new Person();
        person.setAge(18);
        person.setName("范冰冰");
        print(person);
    }

    public static void print(Person person) {
        System.out.println(person.toString());
    }
}

这里只解析Main类编译后的class文件---Main.class

使用javac Main.java命令编译后的class文件内容如下(因为使用javac 命令只能编译当前目录的文件,而Main对象引用了Person对象,会出现编译失败的问题,只需要编译上层文件夹即可 javac build/*。):

cafe babe 0000 0034 003a 0a00 0f00 1f07
0020 0a00 0200 1f0a 0002 0021 0800 220a
0002 0023 0a00 0e00 2409 0025 0026 0a00
0200 270a 0028 0029 0800 2a09 000e 002b
0900 0e00 2c07 002d 0700 2e01 0003 5441
4701 0012 4c6a 6176 612f 6c61 6e67 2f53
7472 696e 673b 0100 056d 5479 7065 0100
0149 0100 063c 696e 6974 3e01 0003 2829
5601 0004 436f 6465 0100 0f4c 696e 654e
756d 6265 7254 6162 6c65 0100 046d 6169
6e01 0016 285b 4c6a 6176 612f 6c61 6e67
2f53 7472 696e 673b 2956 0100 0570 7269
6e74 0100 1128 4c62 7569 6c64 2f50 6572
736f 6e3b 2956 0100 083c 636c 696e 6974
3e01 000a 536f 7572 6365 4669 6c65 0100
094d 6169 6e2e 6a61 7661 0c00 1400 1501
000c 6275 696c 642f 5065 7273 6f6e 0c00
2f00 3001 0009 e88c 83e5 86b0 e586 b00c
0031 0032 0c00 1a00 1b07 0033 0c00 3400
350c 0036 0037 0700 380c 0039 0032 0100
0d54 6869 7320 6973 2061 2074 6167 0c00
1000 110c 0012 0013 0100 0a62 7569 6c64
2f4d 6169 6e01 0010 6a61 7661 2f6c 616e
672f 4f62 6a65 6374 0100 0673 6574 4167
6501 0004 2849 2956 0100 0773 6574 4e61
6d65 0100 1528 4c6a 6176 612f 6c61 6e67
2f53 7472 696e 673b 2956 0100 106a 6176
612f 6c61 6e67 2f53 7973 7465 6d01 0003
6f75 7401 0015 4c6a 6176 612f 696f 2f50
7269 6e74 5374 7265 616d 3b01 0008 746f
5374 7269 6e67 0100 1428 294c 6a61 7661
2f6c 616e 672f 5374 7269 6e67 3b01 0013
6a61 7661 2f69 6f2f 5072 696e 7453 7472
6561 6d01 0007 7072 696e 746c 6e00 2100
0e00 0f00 0000 0200 0900 1000 1100 0000
0900 1200 1300 0000 0400 0100 1400 1500
0100 1600 0000 1d00 0100 0100 0000 052a
b700 01b1 0000 0001 0017 0000 0006 0001
0000 0003 0009 0018 0019 0001 0016 0000
0041 0002 0002 0000 0019 bb00 0259 b700
034c 2b10 12b6 0004 2b12 05b6 0006 2bb8
0007 b100 0000 0100 1700 0000 1600 0500
0000 0900 0800 0a00 0e00 0b00 1400 0c00
1800 0d00 0900 1a00 1b00 0100 1600 0000
2700 0200 0100 0000 0bb2 0008 2ab6 0009
b600 0ab1 0000 0001 0017 0000 000a 0002
0000 0010 000a 0011 0008 001c 0015 0001
0016 0000 0028 0001 0000 0000 000c 120b
b300 0c11 04d2 b300 0db1 0000 0001 0017
0000 000a 0002 0000 0005 0005 0006 0001
001d 0000 0002 001e 

下面解析里面的内容:

Class文件标志符号

CA FE BA BE ----魔术,标识这是一个class文件。 

文件版本号

00 00 ----副版本号

00 34 ----主版本号:52,Java版本号从45(Java1.1)开始,每个大版本发布时,版本号加1,代表这个Class文件可以被JDK 1.8编译,高版本的JDK能向下兼容以前版本的Class文件。

常量池

00 3A ----常量池计数,数值是58。因为它从1开始计数,代表这个Class文件中有57个常量,索引范围1~57。

0A ----10,说明这是一个指向类中方法的符号引用,根据它的表结构可知,接下的4个字节是它的内容。

00 0F ----指向声明方法的类描述符CONSTANT_Class_info的索引项:15。

00 1F ----指向名称及类型描述符CONSTANT_NameAndType的索引项:31。

07 ----7,说明这是一个类或接口的符号引用。根据它的表结构可知,接下的2个字节是它的内容。

00 20 ----指向全限定名常量的索引:32。

0A ----10,说明这是一个指向类中方法的符号引用,根据它的表结构可知,接下的4个字节是它的内容。

00 02 ----指向声明方法的类描述符CONSTANT_Class_info的索引项:2。

00 1F ----指向名称及类型描述符CONSTANT_NameAndType的索引项:31。

0A ----10,说明这是一个指向类中方法的符号引用,根据它的表结构可知,接下的4个字节是它的内容。

00 02 ----指向声明方法的类描述符CONSTANT_Class_info的索引项:2。

00 21 ----指向名称及类型描述符CONSTANT_NameAndType的索引项:33。

08 ----8,说明这是字符串类型字面量,根据它的表结构可知,接下的2个字节是它的内容。

00 22 ----它的索引项是:34。

0A ----10,说明这是一个指向类中方法的符号引用,根据它的表结构可知,接下的4个字节是它的内容。

00 02 ----指向声明方法的类描述符CONSTANT_Class_info的索引项:2。

00 23 ----指向名称及类型描述符CONSTANT_NameAndType的索引项:35。

0A ----10,说明这是一个指向类中方法的符号引用,根据它的表结构可知,接下的4个字节是它的内容。

00 0E ----指向声明方法的类描述符CONSTANT_Class_info的索引项:14。

00 24 ----指向名称及类型描述符CONSTANT_NameAndType的索引项:36。

09 --- 9,说明这是一个字段的符号引用,根据它的表结构可知,接下的4个字节是它的内容。

00 25 ----指向声明字段类型的类或者接口描述符CONSTANT_Class_Info的索引:37,

00 26 ---- 指向字段描述符CONSTANT_NameAndType的索引项:38,

0A ----10,说明这是一个指向类中方法的符号引用,根据它的表结构可知,接下的4个字节是它的内容。

00 02 ----指向声明方法的类描述符CONSTANT_Class_info的索引项:2。

00 27 ----指向名称及类型描述符CONSTANT_NameAndType的索引项:39。

0A ----10,说明这是一个指向类中方法的符号引用,根据它的表结构可知,接下的4个字节是它的内容。

00 28 ----指向声明方法的类描述符CONSTANT_Class_info的索引项:40。

00 29 ----指向名称及类型描述符CONSTANT_NameAndType的索引项:41。

08 ----8,说明这是字符串类型字面量,根据它的表结构可知,接下的2个字节是它的内容。

00 2A ----它的索引项是:42。

09 --- 9,说明这是一个字段的符号引用,根据它的表结构可知,接下的4个字节是它的内容。

00 0E ----指向声明字段类型的类或者接口描述符CONSTANT_Class_Info的索引:14。

00 2B ---- 指向字段描述符CONSTANT_NameAndType的索引项:43。

09 --- 9,说明这是一个字段的符号引用,根据它的表结构可知,接下的4个字节是它的内容。

00 0E ----指向声明字段类型的类或者接口描述符CONSTANT_Class_Info的索引:14。

00 2C ---- 指向字段描述符CONSTANT_NameAndType的索引项:44。

07 ----7,说明这是一个类或接口的符号引用。根据它的表结构可知,接下的2个字节是它的内容。

00 2D ----指向全限定名常量的索引:45。

07 ----7,说明这是一个类或接口的符号引用。根据它的表结构可知,接下的2个字节是它的内容。

00 2E ----指向全限定名常量的索引:46。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 03 ----UTF-8编码的字符串占用的字节数:3。

54 41 47 ----字符串内容,根据ASCII编码表可得到字符串内容:TAG。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 12 ----UTF-8编码的字符串占用的字节数:18。

4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B ----字符串内容,根据ASCII编码表得到字符串:Ljava/lang/String;

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 05 ----UTF-8编码的字符串占用的字节数:5。

6D 54 79 70 65 ----字符串内容,根据ASCII编码表可得到字符串内容:mType。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 01 ----UTF-8编码的字符串占用的字节数:1。

49 ----字符串内容,根据ASCII编码表可得到字符串内容:I。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 06 ----UTF-8编码的字符串占用的字节数:6。

3C 69 6E 69 74 3E----字符串内容,根据ASCII编码表可得到字符串内容:<init>。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 03 ----UTF-8编码的字符串占用的字节数:3。

28 29 56----字符串内容,根据ASCII编码表可得到字符串内容:()V。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 04 ----UTF-8编码的字符串占用的字节数:4。

43 6F 64 65----字符串内容,根据ASCII编码表可得到字符串内容:Code。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 0F ----UTF-8编码的字符串占用的字节数:15。

4C 69 6E 65 4E 75 6D 62 65 72 54 61 62 6C 65----字符串内容,根据ASCII编码表可得到字符串内容:LineNumberTable。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 04 ----UTF-8编码的字符串占用的字节数:4。

6D 61 69 6E ----字符串内容,根据ASCII编码表可得到字符串内容:main。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 16 ----UTF-8编码的字符串占用的字节数:22。

28 5B 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 56 ----字符串内容,根据ASCII编码表可得到字符串内容:(Ljava/lang/String;)V。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 05 ----UTF-8编码的字符串占用的字节数:5。

70 72 69 6E 74 ----字符串内容,根据ASCII编码表可得到字符串内容:print。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 11 ----UTF-8编码的字符串占用的字节数:17。

28 4C 62 75 69 6C 64 2F 50 65 72 73 6F 6E 3B 29 56 ----字符串内容,根据ASCII编码表可得到字符串内容:(Lbuild/Person;)V。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 08 ----UTF-8编码的字符串占用的字节数:8。

3C 63 6C 69 6E 69 74 3E ----字符串内容,根据ASCII编码表可得到字符串内容:<clinit>。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 0A ----UTF-8编码的字符串占用的字节数:10。

53 6F 75 72 63 65 46 69 6C 65 ----字符串内容,根据ASCII编码表可得到字符串内容:SourceFile。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 09 ----UTF-8编码的字符串占用的字节数:9。

4D 61 69 6E 2E 6A 61 76 61 ----字符串内容,根据ASCII编码表可得到字符串内容:Main.java。

0C ----12,说明这是一个字段或方法的符号引用,根据它的表结构可知,接下的4个字节是它的内容。

00 14 ----指向该字段或方法名称常量项的索引:20。

00 15 ----指向该字段或方法描述符常量项的索引:21。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 0C ----UTF-8编码的字符串占用的字节数:12。

62 75 69 6C 64 2F 50 65 72 73 6F 6E ----字符串内容,根据ASCII编码表可得到字符串内容:build/Person。

0C ----12,说明这是一个字段或方法的符号引用,根据它的表结构可知,接下的4个字节是它的内容。

00 2F ----指向该字段或方法名称常量项的索引:47。

00 30 ----指向该字段或方法描述符常量项的索引:48。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 09 ----UTF-8编码的字符串占用的字节数:9。

E8 8C 83 E5 86 B0 E5 86 B0 ----字符串内容,根据ASCII编码表可得到字符串内容:范冰冰。

0C ----12,说明这是一个字段或方法的符号引用,根据它的表结构可知,接下的4个字节是它的内容。

00 31  ----指向该字段或方法名称常量项的索引:49。

00 32 ----指向该字段或方法描述符常量项的索引:50。

0C ----12,说明这是一个字段或方法的符号引用,根据它的表结构可知,接下的4个字节是它的内容。

00 1A  ----指向该字段或方法名称常量项的索引:26。

00 1B ----指向该字段或方法描述符常量项的索引:27。

07 ----7,说明这是一个类或接口的符号引用。根据它的表结构可知,接下的2个字节是它的内容。

00 33 ----指向全限定名常量的索引:51。

0C ----12,说明这是一个字段或方法的符号引用,根据它的表结构可知,接下的4个字节是它的内容。

00 34  ----指向该字段或方法名称常量项的索引:52。

00 35 ----指向该字段或方法描述符常量项的索引:53。

0C ----12,说明这是一个字段或方法的符号引用,根据它的表结构可知,接下的4个字节是它的内容。

00 36  ----指向该字段或方法名称常量项的索引:54。

00 37 ----指向该字段或方法描述符常量项的索引:55。

07 ----7,说明这是一个类或接口的符号引用。根据它的表结构可知,接下的2个字节是它的内容。

00 38 ----指向全限定名常量的索引:56。

0C ----12,说明这是一个字段或方法的符号引用,根据它的表结构可知,接下的4个字节是它的内容。

00 39  ----指向该字段或方法名称常量项的索引:57。

00 32 ----指向该字段或方法描述符常量项的索引:50。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 0D ----UTF-8编码的字符串占用的字节数:13。

54 68 69 73 20 69 73 20 61 20 74 61 67 ----字符串内容,根据ASCII编码表可得到字符串内容:This is a tag。

0C ----12,说明这是一个字段或方法的符号引用,根据它的表结构可知,接下的4个字节是它的内容。

00 10  ----指向该字段或方法名称常量项的索引:16。

00 11 ----指向该字段或方法描述符常量项的索引:17。

0C ----12,说明这是一个字段或方法的符号引用,根据它的表结构可知,接下的4个字节是它的内容。

00 12  ----指向该字段或方法名称常量项的索引:18。

00 13 ----指向该字段或方法描述符常量项的索引:19。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 0A ----UTF-8编码的字符串占用的字节数:10。

62 75 69 6C 64  2F 4D 61 69 6E ----字符串内容,根据ASCII编码表可得到字符串内容:Build/Main。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 10 ----UTF-8编码的字符串占用的字节数:16。

6A 61 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74----字符串内容,根据ASCII编码表可得到字符串内容:java/lang/Object。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 06 ----UTF-8编码的字符串占用的字节数:6。

73 65 74 41 67 65----字符串内容,根据ASCII编码表可得到字符串内容:setAge。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 04 ----UTF-8编码的字符串占用的字节数:4。

28 49 29 56----字符串内容,根据ASCII编码表可得到字符串内容:(I)V。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 07 ----UTF-8编码的字符串占用的字节数:7。

73 65 74 4E 61 6D 65----字符串内容,根据ASCII编码表可得到字符串内容:setName。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 15 ----UTF-8编码的字符串占用的字节数:21。

28 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 56 ----字符串内容,根据ASCII编码表可得到字符串内容:(Ljava/lang/String;)V。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 10 ----UTF-8编码的字符串占用的字节数:16。

6A 61 76 61 2F 6C 61 6E 67 2F 53 79 73 74 65 6D ----字符串内容,根据ASCII编码表可得到字符串内容:java/lang/System。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 03 ----UTF-8编码的字符串占用的字节数:3。

6F 75 74 ----字符串内容,根据ASCII编码表可得到字符串内容:out。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 15 ----UTF-8编码的字符串占用的字节数:21。

4C 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72 65 61 6D 3B ----字符串内容,根据ASCII编码表可得到字符串内容:Ljava/io/PrintSystem;。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 08 ----UTF-8编码的字符串占用的字节数:8。

74 6F 53 74 72 69 6E 67 ----字符串内容,根据ASCII编码表可得到字符串内容:toString。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 14 ----UTF-8编码的字符串占用的字节数:20。

28 29 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B  ----字符串内容,根据ASCII编码表可得到字符串内容:()Ljava/lang/String;。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 13 ----UTF-8编码的字符串占用的字节数:19。

6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72  ----字符串内容,根据ASCII编码表可得到字符串内容:java/io/PrintStream。

01 ----1,说明这是一个UTF-8编码的字符串,根据它的表结构可知,接下的2个字节是它的长度。

00 07----UTF-8编码的字符串占用的字节数:7。

70 72 69 6E 74 6C 6E  ----字符串内容,根据ASCII编码表可得到字符串内容:println。

00 21----访问标志,标识这是一个普通的Java类,不是接口、枚举或注解,被public关键字修饰但没有被声明为final和abstrace。

00 0E ----类索引,表明这个类的全限定名,索引值为14。

00 0F ----父类索引,表明这个类的父类的全限定名,索引值为15。

00 00 ---- 接口计数器,说明这个类中没有接口,也就没有接口索引集合。

内容解析到这,我们可以得到一个常量列表:

   #1 = Methodref          #15.#31        // java/lang/Object."<init>":()V
   #2 = Class              #32            // build/Person
   #3 = Methodref          #2.#31         // build/Person."<init>":()V
   #4 = Methodref          #2.#33         // build/Person.setAge:(I)V
   #5 = String             #34            // 范冰冰
   #6 = Methodref          #2.#35         // build/Person.setName:(Ljava/lang/String;)V
   #7 = Methodref          #14.#36        // build/Main.print:(Lbuild/Person;)V
   #8 = Fieldref           #37.#38        // java/lang/System.out:Ljava/io/PrintStream;
   #9 = Methodref          #2.#39         // build/Person.toString:()Ljava/lang/String;
  #10 = Methodref          #40.#41        // java/io/PrintStream.println:(Ljava/lang/String;)V
  #11 = String             #42            // This is a tag
  #12 = Fieldref           #14.#43        // build/Main.TAG:Ljava/lang/String;
  #13 = Fieldref           #14.#44        // build/Main.mType:I
  #14 = Class              #45            // build/Main
  #15 = Class              #46            // java/lang/Object
  #16 = Utf8               TAG
  #17 = Utf8               Ljava/lang/String;
  #18 = Utf8               mType
  #19 = Utf8               I
  #20 = Utf8               <init>
  #21 = Utf8               ()V
  #22 = Utf8               Code
  #23 = Utf8               LineNumberTable
  #24 = Utf8               main
  #25 = Utf8               ([Ljava/lang/String;)V
  #26 = Utf8               print
  #27 = Utf8               (Lbuild/Person;)V
  #28 = Utf8               <clinit>
  #29 = Utf8               SourceFile
  #30 = Utf8               Main.java
  #31 = NameAndType        #20:#21        // "<init>":()V
  #32 = Utf8               build/Person
  #33 = NameAndType        #47:#48        // setAge:(I)V
  #34 = Utf8               范冰冰
  #35 = NameAndType        #49:#50        // setName:(Ljava/lang/String;)V
  #36 = NameAndType        #26:#27        // print:(Lbuild/Person;)V
  #37 = Class              #51            // java/lang/System
  #38 = NameAndType        #52:#53        // out:Ljava/io/PrintStream;
  #39 = NameAndType        #54:#55        // toString:()Ljava/lang/String;
  #40 = Class              #56            // java/io/PrintStream
  #41 = NameAndType        #57:#50        // println:(Ljava/lang/String;)V
  #42 = Utf8               This is a tag
  #43 = NameAndType        #16:#17        // TAG:Ljava/lang/String;
  #44 = NameAndType        #18:#19        // mType:I
  #45 = Utf8               build/Main
  #46 = Utf8               java/lang/Object
  #47 = Utf8               setAge
  #48 = Utf8               (I)V
  #49 = Utf8               setName
  #50 = Utf8               (Ljava/lang/String;)V
  #51 = Utf8               java/lang/System
  #52 = Utf8               out
  #53 = Utf8               Ljava/io/PrintStream;
  #54 = Utf8               toString
  #55 = Utf8               ()Ljava/lang/String;
  #56 = Utf8               java/io/PrintStream
  #57 = Utf8               println

有了常量池,我们就可以解析我们编写的类、变量、以及Java字节码。

字段(变量)集合

00 02 ----类中的变量个数:2

00 09 ----第一个字段的access_flags标识:9,说明这是一个public static 修饰的变量。

00 10 ----字段的简单名称索引:16。

00 11 ----字段的描述符索引:17。

00 00 ----字段的额外属性数量:0,说明这个字段没有额外属性。

00 09 ----第二个字段的access_flags标识:9,说明这是一个public static 修饰的变量。

00 12 ----字段的简单名称索引:18。

00 13 ----字段的描述符索引:19。

00 00 ----字段的额外属性数量:0,说明这个字段没有额外属性。

方法集合

00 04 ----类中方法的数量是:4。

00 01 ----第一个方法的access_flags标识:1,说明这是一个public 修饰的方法。

00 14 ----方法的简单名称索引:20。

00 15 ----方法的描述符索引:21。

00 01 ----方法的属性表集合有一项属性

00 16 ---- attribute_name_index,方法的属性索引:22,可知它是Code属性。

00 00 00 1D ----attribute_length,属性长度是:29。

00 01 ----max_stack,操作数栈深度的最大值为:1。

00 01 ----max_locals,局部变量表所需的存储空间:1(Slot)。

00 00 00 05 ---- code_length,Java源程序编译后生成的字节码指令长度:5。

2A  B7 00 01 B1 ----code,字节码指令的一系列字节流,每个指令是一个u1类型的单字节。

00 00 ---- exception_table_length,异常处理表长度:0,表示没有异常表。

00 01 ---- attributes_count,Code属性的属性表数量为:1

00 17 ----属性索引为:23,表明这是一个LineNumberTable属性,用于描述Java源码行号与字节码行号之间的对应关系。

00 00 00 06 ----属性长度:6。

00 01 ---- line_number_table_length,LineNumberTable长度:1。

00 00 ----数据项,字节码行号:0。

00 03 ----Java源码行号:3。

00 09 ----第二个方法的修饰符:9,表明这是一个 public static 类型的方法。

00 18 ----方法的简单名称索引:24。

00 19 ----方法的描述符名称索引:25。

00 01 ----这个方法有一个属性表。

00 16 ---- 属性表的索引是:22,表明接下来的是方法字节码。

00 00 00 41 ---- 属性值长度:65。

00 02 ----max_stack,操作数栈深度的最大值为:2。

00 02 ----max_locals,局部变量表所需的存储空间:2(Slot)。

00 00 00 19 ---- code_length,Java源程序编译后生成的字节码指令长度:25。

BB 00 02 59 B7 00 03 4C 2B 10 12 B6 00 04 2B 12 05 B6 00 06 2B B8 00 07 B1 ----code,字节码指令的一系列字节流,每个指令是一个u1类型的单字节。

00 00 ---- exception_table_length,异常处理表长度:0,表示没有异常表。

00 01 ---- attributes_count,Code属性的属性表数量为:1

00 17 ----属性索引为:23,表明这是一个LineNumberTable属性,用于描述Java源码行号与字节码行号之间的对应关系。

00 00 00 16----属性长度:22。

00 05 ---- line_number_table_length,LineNumberTable长度:5。

00 00 00 03----数据项,字节码行号:0,对应的Java源码行号:3。

00 08 00 0A ----数据项,字节码行号:8,对应的Java源码行号:10。

00 0E 00 0B ----数据项,字节码行号:14,对应的Java源码行号:11。

00 14 00 0C ----数据项,字节码行号:20,对应的Java源码行号:12。

00 18 00 0D ----数据项,字节码行号:24,对应的Java源码行号:13。

00 09 ----第三个方法的修饰符:9,表明这是一个 public static 类型的方法。

00 1A ----方法的简单名称索引:26。

00 1B ----方法的描述符名称索引:27。

00 01 ----这个方法有一个属性表。

00 16 ---- 属性表的索引是:22,表明接下来的是Code属性表。

00 00 00 27 ---- 属性值长度:39。

00 02 ----max_stack,操作数栈深度的最大值为:2。

00 01 ----max_locals,局部变量表所需的存储空间:1(Slot)。

00 00 00 0B ---- code_length,Java源程序编译后生成的字节码指令长度:11。

B2 00 08 2A B6 00 09 B6 00 0A B1 ----code,字节码指令的一系列字节流,每个指令是一个u1类型的单字节。

00 00 ---- exception_table_length,异常处理表长度:0,表示没有异常表。

00 01 ---- attributes_count,Code属性的属性表数量为:1

00 17 ----属性索引为:23,表明这是一个LineNumberTable属性,用于描述Java源码行号与字节码行号之间的对应关系。

00 00 00 0A----属性长度:10。

00 02 ---- line_number_table_length,LineNumberTable长度:2。

00 00 00 10----数据项,字节码行号:0,对应的Java源码行号:16。

00 0A 00 11 ----数据项,字节码行号:10,对应的Java源码行号:17。

00 08 ----第四个方法的修饰符:9,表明这是一个 static 类型的方法。

00 1C ----方法的简单名称索引:28。

00 15 ----方法的描述符名称索引:21。

00 01 ----这个方法有一个属性表。

00 16 ---- 属性表的索引是:22,表明接下来的是Code属性表。

00 00 00 28 ---- 属性值长度:40。

00 01 ----max_stack,操作数栈深度的最大值为:1。

00 00 ----max_locals,局部变量表所需的存储空间:0(Slot)。

00 00 00 0C ---- code_length,Java源程序编译后生成的字节码指令长度:12。

12 0B B3 00 0C 11 04 D2 B3 00 0D B1  ----code,字节码指令的一系列字节流,每个指令是一个u1类型的单字节。

00 00 ---- exception_table_length,异常处理表长度:0,表示没有异常表。

00 01 ---- attributes_count,Code属性的属性表数量为:1

00 17 ----属性索引为:23,表明这是一个LineNumberTable属性,用于描述Java源码行号与字节码行号之间的对应关系。

00 00 00 0A----属性长度:10。

00 02 ---- line_number_table_length,LineNumberTable长度:2。

00 00 00 05----数据项,字节码行号:0,对应的Java源码行号:5。

00 05 00 06 ----数据项,字节码行号:5,对应的Java源码行号:6。

内容解析到这里,我们可以得到类中的变量以及方法有:

{
  public static java.lang.String TAG;
    descriptor: Ljava/lang/String;
    flags: ACC_PUBLIC, ACC_STATIC

  public static int mType;
    descriptor: I
    flags: ACC_PUBLIC, ACC_STATIC

  public build.Main();
    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 3: 0

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: new           #2                  // class build/Person
         3: dup
         4: invokespecial #3                  // Method build/Person."<init>":()V
         7: astore_1
         8: aload_1
         9: bipush        18
        11: invokevirtual #4                  // Method build/Person.setAge:(I)V
        14: aload_1
        15: ldc           #5                  // String 范冰冰
        17: invokevirtual #6                  // Method build/Person.setName:(Ljava/lang/String;)V
        20: aload_1
        21: invokestatic  #7                  // Method print:(Lbuild/Person;)V
        24: return
      LineNumberTable:
        line 9: 0
        line 10: 8
        line 11: 14
        line 12: 20
        line 13: 24

  public static void print(build.Person);
    descriptor: (Lbuild/Person;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: aload_0
         4: invokevirtual #9                  // Method build/Person.toString:()Ljava/lang/String;
         7: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        10: return
      LineNumberTable:
        line 16: 0
        line 17: 10

  static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=1, locals=0, args_size=0
         0: ldc           #11                 // String This is a tag
         2: putstatic     #12                 // Field TAG:Ljava/lang/String;
         5: sipush        1234
         8: putstatic     #13                 // Field mType:I
        11: return
      LineNumberTable:
        line 5: 0
        line 6: 5
}

附加属性

00 01 ----附加属性数量:1个。

00 1D ----附加属性索引:29,表明这是一个SourceFile,用来记录生成这个Class文件的源码文件名称。

00 00 00 02 ---- 属性长度:2。

00 1E ----源码文件名称索引:30。

附加属性的内容:

SourceFile: "Main.java"

至此,一个Class文件翻译完毕。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值