学习java字节码

学习原文链接

写一个Demo.java代码如下

1
2
3
4
5
6
public class Demo{
private int aa=1;
void testMethod(){
//do nothing
}
}

执行javac Demo.java后,查看Demo.class文件,得到如下内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
cafe babe 0000 0034 0012 0a00 0400 0e09
0003 000f 0700 1007 0011 0100 0261 6101
0001 4901 0006 3c69 6e69 743e 0100 0328
2956 0100 0443 6f64 6501 000f 4c69 6e65
4e75 6d62 6572 5461 626c 6501 000a 7465
7374 4d65 7468 6f64 0100 0a53 6f75 7263
6546 696c 6501 0009 4465 6d6f 2e6a 6176
610c 0007 0008 0c00 0500 0601 0004 4465
6d6f 0100 106a 6176 612f 6c61 6e67 2f4f
626a 6563 7400 2100 0300 0400 0000 0100
0200 0500 0600 0000 0200 0100 0700 0800
0100 0900 0000 2600 0200 0100 0000 0a2a
b700 012a 04b5 0002 b100 0000 0100 0a00
0000 0a00 0200 0000 0100 0400 0200 0000
0b00 0800 0100 0900 0000 1900 0000 0100
0000 01b1 0000 0001 000a 0000 0006 0001
0000 0005 0001 000c 0000 0002 000d

盗图-> 格式图

  • 都是十六进制的东西,前面四个字节为魔数,值固定为0xcafe babe

  • 接下来2+2个字节,为java版本号,0000是次版本号,0034是主版本号,0034转成十进制为52,对应1.8.0

  • 接下来2+n字节为常量池,常量池包括字面量和符号引用。0012代表常量池的数量,十进制表示就是有17个。其中0项保留。

    盗图-> 常量类型表

    0012代表常量池的数量,从这个表明class的常量池最大长度为65535,我也试过,当变量声明为7w个的时候,编译会报常量过多的错误。

  • 常量1:对照上表,接下第一个是U1类型的数据代表常量,分析0a,转化成十进制为10,查表可知道是MethodRef_info;从表格可以得知接下来是一个U2,表明方法的类描述符的索引(即0004十进制4),然后是世象名称及类型性描述符(即CONSTANT_NameAndType_info索引000e,十进制14)

  • 常量2,Tag(09,十进制09)查表可知是CONSTANT_Fieldref_info(然后是CONTANT_Class_info索引0003),CONTANT_NameAndType_info(000f,十进制16)

  • 常量3(0700 10),Tag(07,CONSTANT_Class_info),全限定名常量项索引(0010)

  • 常量4(07 0011),Tag(07,CONSTANT_Class_info),全限定名常量项索引(0011)

  • 常量5(0100 026161),Tag(01,CONTANT_Utf8_info),UTF-8长度(length:0002),长度为length的UTF-8字符串(61就是ASCII的‘a’),因为长度为2,所以还有一个61,即‘a’;(从这里可以看出,变量名的命名长度最长不能超过两字节)

  • 常量6(010001 49),Tag(01,CONTANT_Utf8_info),length:1,值:49即“l”

  • 常量7(01 0006 3c69 6e69 743e),Tag(01),length:0006;字符(3c->’<’)(69->’i’)(6e->’n’)(69->’i’)(74->’t’)(3e->’>’)合起来就是‘’;具体都是查ASCALL表得到的

  • 常量8(0100 0328 2956),TAG(01),length:0003,字符:(28->’(‘)(29->’)’)(56->’V’),合起来就是()V

  • 常量9 (0100 0443 6f64 65)TAG(01),length:0004,字符43->’C’;6f->’o’;64->’d’;65->’e’;合起来Code

  • 常量10(01 000f 4c69 6e65 4e75 6d62 6572 5461 62 6c65),TAG(01),length:15.最后合起来是‘LineNumberTable

  • 常量11 略~

  • 省略翻译部分常量,当常量都完了之后,进入00 21

    盗图->标志位

0021说是0020和0001的并集。所以声明为public类型,。。。

0003类索引引用第三个常量,这两第三个常量引用16常量。最后定位为包名

等等。大概了解到这里就够了。