java 字节码解析

没看到网上有完整的字节码解析,一般都是讲部分,这里就对一个简单的java文件的字节码进行了解析,基本是自己推的,希望有用

 

java代码

public class ClassTest{

	int a = 1;
	static int b = 10;

	static void test(){
		b ++;
	}

	void test2(){
		a ++;
	}
}

再说说怎么查看字节码文件把

首先新建一个java后缀的文件,名字为ClassTest

cmd进入该文件的目录

执行javac ClassTest.java,该目录下会生成一个同名的class后缀的文件

打开该文件,就可以查看16进制的class文件了

 

当然也可以直接反编译

javap -verbose ClassTest.class(verbose可以查看更为详细的信息)

Classfile /F:/jvm/ClassTest.class
  Last modified 2019-6-23; size 423 bytes
  MD5 checksum 5ed4fafcf93f26b3235d1c6608fb7874
  Compiled from "ClassTest.java"
public class ClassTest
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #5.#18         // java/lang/Object."<init>":()V
   #2 = Fieldref           #4.#19         // ClassTest.a:I
   #3 = Fieldref           #4.#20         // ClassTest.b:I
   #4 = Class              #21            // ClassTest
   #5 = Class              #22            // java/lang/Object
   #6 = Utf8               a
   #7 = Utf8               I
   #8 = Utf8               b
   #9 = Utf8               <init>
  #10 = Utf8               ()V
  #11 = Utf8               Code
  #12 = Utf8               LineNumberTable
  #13 = Utf8               test
  #14 = Utf8               test2
  #15 = Utf8               <clinit>
  #16 = Utf8               SourceFile
  #17 = Utf8               ClassTest.java
  #18 = NameAndType        #9:#10         // "<init>":()V
  #19 = NameAndType        #6:#7          // a:I
  #20 = NameAndType        #8:#7          // b:I
  #21 = Utf8               ClassTest
  #22 = Utf8               java/lang/Object
{
  int a;
    descriptor: I
    flags:

  static int b;
    descriptor: I
    flags: ACC_STATIC

  public ClassTest();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: iconst_1
         6: putfield      #2                  // Field a:I
         9: return
      LineNumberTable:
        line 1: 0
        line 3: 4

  static void test();
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=2, locals=0, args_size=0
         0: getstatic     #3                  // Field b:I
         3: iconst_1
         4: iadd
         5: putstatic     #3                  // Field b:I
         8: return
      LineNumberTable:
        line 7: 0
        line 8: 8

  void test2();
    descriptor: ()V
    flags:
    Code:
      stack=3, locals=1, args_size=1
         0: aload_0
         1: dup
         2: getfield      #2                  // Field a:I
         5: iconst_1
         6: iadd
         7: putfield      #2                  // Field a:I
        10: return
      LineNumberTable:
        line 11: 0
        line 12: 10

  static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=1, locals=0, args_size=0
         0: bipush        10
         2: putstatic     #3                  // Field b:I
         5: return
      LineNumberTable:
        line 4: 0
}
SourceFile: "ClassTest.java"
 

以下是字节码原文

cafe babe 0000 0034 0017 0a00 0500 1209
0004 0013 0900 0400 1407 0015 0700 1601
0001 6101 0001 4901 0001 6201 0006 3c69
6e69 743e 0100 0328 2956 0100 0443 6f64
6501 000f 4c69 6e65 4e75 6d62 6572 5461
626c 6501 0004 7465 7374 0100 0574 6573
7432 0100 083c 636c 696e 6974 3e01 000a
536f 7572 6365 4669 6c65 0100 0e43 6c61
7373 5465 7374 2e6a 6176 610c 0009 000a
0c00 0600 070c 0008 0007 0100 0943 6c61
7373 5465 7374 0100 106a 6176 612f 6c61
6e67 2f4f 626a 6563 7400 2100 0400 0500
0000 0200 0000 0600 0700 0000 0800 0800
0700 0000 0400 0100 0900 0a00 0100 0b00
0000 2600 0200 0100 0000 0a2a b700 012a
04b5 0002 b100 0000 0100 0c00 0000 0a00
0200 0000 0100 0400 0300 0800 0d00 0a00
0100 0b00 0000 2500 0200 0000 0000 09b2
0003 0460 b300 03b1 0000 0001 000c 0000
000a 0002 0000 0007 0008 0008 0000 000e
000a 0001 000b 0000 0027 0003 0001 0000
000b 2a59 b400 0204 60b5 0002 b100 0000
0100 0c00 0000 0a00 0200 0000 0b00 0a00
0c00 0800 0f00 0a00 0100 0b00 0000 1e00
0100 0000 0000 0610 0ab3 0003 b100 0000
0100 0c00 0000 0600 0100 0000 0400 0100
1000 0000 0200 11

这个看起来很舒服把,但是不知道咋来的可不行,下面解析一下

解析之后对于字节码指令有更好的理解

ca fe ba be //魔数

00 00 00 34 //版本号52

//常量池
00 17 //常量池的数量,数值为23,数量为22个(因为从1开始计数)
//#1
0a //tag值,代表这是什么类型的项目,数值为10,也就是CONSTANT_Methodref_info,类中方法的符号引用
00 05 //index,代表指向声明方法的类描述符CONSTANT_Class_info的索引项,这里指向#5
00 12 //index,代表指向名称及类型描述符CONSTANT_NameAndType的索引项,这里指向#18

//#2
09 //tag值,数值为9,字段的符号引用
00 04 //字段的类或者接口描述符的索引项,这里指向#4
00 13 //字段描述符CONSTANT_NameAndType的索引项

//#3
09 //tag值,数值为9,字段的符号引用
00 04 //字段的类或者接口描述符的索引项,这里指向#4
00 14 //字段描述符CONSTANT_NameAndType的索引项,这里指向#20

//#4
07 //tag值,表明这是类或者接口的符号引用
00 15 //指向全限定名常量项的索引,这里指向#21

//#5
07 //tag值,表明这是类或者接口的符号引用
00 16 //指向全限定名常量项的索引,这里指向#22

//#6
01 //tag值,表明这是UTF-8编码的字符串
00 01 //字符串的长度,这里为1
61 //Ascii码,这里为a

//#7
01 //tag值,表明这是UTF-8编码的字符串
00 01 //字符串的长度,这里为1
49 //Ascii码,这里为I

//#8
01 //tag值,表明这是UTF-8编码的字符串
00 01 //字符串的长度,这里为1
62 //Ascii码,这里为b

//#9
01 //tag值,表明这是UTF-8编码的字符串
00 06 //字符串的长度,这里为6
3c 69 6e 69 74 3e //Ascii码,这里为<init>

//#10
01 //tag值,表明这是UTF-8编码的字符串
00 03 //字符串的长度,这里为3
28 29 56 //Ascii码,这里为()V

01 //tag值,表明这是UTF-8编码的字符串#11
00 04 //字符串的长度,这里为4
43 6f 64 65 //Ascii码,这里为Code

//#12
01 //tag值,表明这是UTF-8编码的字符串
00 0f //字符串的长度,这里为15
4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c 65 //Ascii码,这里为LineNumberTable

//#13
01 //tag值,表明这是UTF-8编码的字符串
00 04 //字符串的长度,这里为4
74 65 73 74 //Ascii码,这里为test

//#14
01 //tag值,表明这是UTF-8编码的字符串,
00 05 //字符串的长度,这里为5
74 65 73 74 32 //Ascii码,这里为test2

//#15
01 //tag值,表明这是UTF-8编码的字符串,
00 08 //字符串的长度,这里为8
3c 63 6c 69 6e 69 74 3e //Ascii码,这里为<clinit>

//#16
01 //tag值,表明这是UTF-8编码的字符串
00 0a //字符串的长度,这里为10
53 6f 75 72 63 65 46 69 6c 65 //Ascii码,这里为SourceFile

//#17
01 //tag值,表明这是UTF-8编码的字符串
00 0e //字符串的长度,这里为14
43 6c 61 73 73 54 65 73 74 2e 6a 61 76 61 //ClassTest.java

//#18
0c //tag值,12,表明这是CONSATNT_NameAndType_info
00 09 //指向该字段或者方法名称常量池的索引,这里指向#9
00 0a //指向该字段或者方法描述符常量项的索引,这里指向#10

//#19
0c //tag值,12,表明这是CONSATNT_NameAndType_info
00 06 //指向该字段或者方法名称常量池的索引,这里指向#6
00 07 //指向该字段或者方法描述符常量项的索引,这里指向#7

//#20
0c //tag值,12,表明这是CONSATNT_NameAndType_info
00 08 //指向该字段或者方法名称常量池的索引,这里指向#8
00 07 //指向该字段或者方法描述符常量项的索引,这里指向#7

//#21
01 //tag值,表明这是UTF-8编码的字符串
00 09 //字符串的长度,这里为9
43 6c 61 73 73 54 65 73 74 //Ascii码,这里为ClassTest

//#22
01 //tag值,表明这是UTF-8编码的字符串
00 10 //字符串的长度,这里为16
6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 //Ascii码,这里为java/lang/Object

00 21 //访问标志,public类型

00 04 //类索引,指向常量池中的类描述符,这里指向#4
00 05 //父类索引,指向常量池中的类描述符,这里指向#5
00 00 //接口索引集合的个数,0

00 02 //字段表的数量,2
//第一个字段
00 00 //访问标识符
00 06 //简单名称索引,这里指向#6
00 07 //字段的描述符索引,这里指向#7
00 00 //属性的个数,0

//第二个字段
00 08 //访问标识符,static
00 08 //简单名称索引,这里指向8
00 07 //字段的描述符索引,这里指向#7
00 00 //属性的个数,0

00 04 //方法表的个数
//第一个方法
00 01 //访问标识符,public
00 09 //简单名称的索引,这里指向#9
00 0a //方法描述符的索引,这里指向#10
00 01 //属性的个数,1个
00 0b //属性名称索引,这里指向#11(这里为Code属性,info里面的信息也就是code的信息)
00 00 00 26 //属性的长度,38
00 02 //最大栈深,2
00 01 //局部变量表所需的存储空间,单位为slot,这里是1个slot
00 00 00 0a //code的具体长度为10
2a b7 00 01 2a 04 b5 00 02 b1 //字节码
//字节码的解释
//2a对应的字节码为aload_0,代表将第0个slot中的为reference类型的本地变量推送到操作数栈顶
//b7对应的字节码为invokespecial,代表以栈顶为reference类型的数据所指向的对象作为方法接收者,调用此对象的实例构造器方法、private方法或者他的父类方法;会有一个u2参数说明具体调用哪一个方法,u2代表方法的符号引用
//00 01为invokespecial的参数,也就是指向一个方法的符号引用,这里是#1,指向的是<init>构造方法
//2a对应的字节码为aload_0,代表将第0个slot中的为reference类型的本地变量推送到操作数栈顶
//04对应的字节码为iconst_1,代表将int型1推送到栈顶
//b5对应的字节码为putfield,代表为指定的类的实例域赋值;下面跟着u2,也就是字段的符号引用;赋给这个字段的值,以及包含这个字段的对象引用,在执行这条指令的时候,都 会从操作数栈顶上pop出来
//00 02为putfield的参数,也就是指向一个字段的符号引用,治理是#2,指向的是a
//b1字节码为return,代表从当前方法返回void
00 00 //异常处理表的大小,这里为0
00 01 //参数的个数,这里为1个?
00 0c //属性的名称索引(这里为LineNumberTable属性)
00 00 00 0a //属性的长度,这里为10
00 02 //行号表的长度,这里为2
00 00 //start_pc,字节码行号这里为0
00 01 //line-number,java源码行号,这里为1
00 04 //start_pc,字节码行号这里为4
00 03 //line-number,java源码行号,这里为3

//第二个方法
00 08 //访问标识符,static
00 0d //简单名称的索引,这里指向#13
00 0a //方法描述符的索引,这里指向#10
00 01 //属性的个数,1个
00 0b //属性名称索引,这里指向#11(这里为Code属性,info里面的信息也就是code的信息)
00 00 00 25 //属性的长度,37
00 02 //最大栈深,2
00 00 //局部变量表所需的存储空间,单位为slot,这里是0个slot
00 00 00 09 //code的具体长度为9
b2 00 03 04 60 b3 00 03 b1 //字节码
//字节码的解释
//b2对应的字节码为getstatic,表明获取指定类的静态域,并将其值压入栈顶;后面跟着u2,代表获取的字段的符号引用
//00 03;getstaic的参数,代表一个字段的符号引用
//04对应的字节码为iconst_1;代表将int型1推送到栈顶
//60对应的字节码为iadd,代表将栈顶两int型数值相加并将结果压入栈顶
//b3对应的字节码为putstaic,代表为指定的类的静态域赋值;有以一个u2参数,代表字段的符号引用
//00 03,putstatic的参数,代表一个字段的符号引用
//b1,对应的字节码为reurn,代表返回void
00 00 //异常处理表的大小,这里为0
00 01 //参数的个数,这里为1个?
00 0c //属性的名称索引(这里为LineNumberTable属性)
00 00 00 0a //属性的长度,这里为10
00 02 //行号表的长度,这里为2
00 00 //start_pc,字节码行号这里为0
00 07 //line-number,java源码行号,这里为7
00 08 //start_pc,字节码行号这里为0
00 08 //line-number,java源码行号,这里为7

//第三个方法
00 00 //访问标识符,default
00 0e //简单名称的索引,这里指向#14
00 0a //方法描述符的索引,这里指向#10
00 01 //属性的个数,1个
00 0b //属性名称索引,这里指向#11(这里为Code属性,info里面的信息也就是code的信息)
00 00 00 27 //属性的长度,39
00 03 //最大栈深,3
00 01 //局部变量表所需的存储空间,单位为slot,这里是1个slot
00 00 00 0b //code的具体长度为11
2a 59 b4 00 02 04 60 b5 00 02 b1 //字节码
//字节码的解释
//2a对应的字节码为aload_0,代表将第0个slot中的为reference类型的本地变量推送到操作数栈顶
//59对应的字节码为dup,代表复制栈顶的数值,并且将其压入栈顶
//b4对应的字节码为getfield,代表获取指定类的实例域,并将其压入栈;有一个u2参数,代表字段的符号引用;对象引用,在执行这条指令的时候,会从操作数栈顶上pop出来
//00 02,getfield的参数,代表一个字段的符号引用
//04对应的字节码为iconst_1;代表将int型1推送到栈顶
//60对应的字节码为iadd,代表将栈顶两int型数值相加并将结果压入栈顶
//b5对应的字节码为putfield,代表为指定的类的实例域赋值;下面跟着u2,也就是字段的符号引用;赋给这个字段的值,以及包含这个字段的对象引用,在执行这条指令的时候,都 会从操作数栈顶上pop出来
//00 02为putfield的参数,也就是指向一个字段的符号引用,这里是#2,指向的是a
//b1,对应的字节码为reurn,代表返回void
00 00 //异常处理表的大小,这里为0
00 01 /参数的个数,这里为1个?
00 0c //属性的名称索引(这里为LineNumberTable属性)
00 00 00 0a //属性的长度,这里为10
00 02 //行号表的长度,这里为2
00 00 //start_pc,字节码行号这里为0
00 0b //line-number,java源码行号,这里为11
00 0a //start_pc,字节码行号这里为10
00 0c //line-number,java源码行号,这里为12

//第四个方法
00 08 //访问标识符,static
00 0f //简单名称的索引,这里指向#15
00 0a //方法描述符的索引,这里指向#10
00 01 //属性的个数,1个
00 0b //属性名称索引,这里指向#11(这里为Code属性,info里面的信息也就是code的信息)
00 00 00 1e //属性的长度,30
00 01 //最大栈深,1
00 00 //局部变量表所需的存储空间,单位为slot,这里是0个slot
00 00 00 06 //code的具体长度为6
10 0a b3 00 03 b1//字节码
//10代表的字节码为bipush,代表将单字节的常量值(-128-127)推送到栈顶;后面跟一个参数,也就是具体的值
//0a,bipush的参数,也就是整数10
//b3对应的字节码为putstatic,代表为指定的类的静态域赋值;有以一个u2参数,代表字段的符号引用
//00 03,putstatic的参数,一个字段的符号引用
//b1,对应的字节码为reurn,代表返回void
00 00 //异常处理表的大小,这里为0
00 01 //参数的个数,这里为1个?
00 0c //属性的名称索引(这里为LineNumberTable属性)
00 00 00 06 //属性的长度,这里为10
00 01 //行号表的长度,这里为2
00 00 //start_pc,字节码行号这里为0
00 04 //line-number,java源码行号,这里为11

00 01

00 10 //属性名称索引,这里为#16,SorceFile
00 00 00 02 //属性的长度,这里为2
00 11 //源文件名字的索引,这里指向#17

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值