JAVA 字节码学习

代码为 
public class Hello {
	private int test;
    public int my(){
          return test;
      }
}

编译后的class文件
CA FE BA BE 00 00 00 34  00 16 07 00 02 01 00 05 
48 65 6C 6C 6F 07 00 04  01 00 10 6A 61 76 61 2F
6C 61 6E 67 2F 4F 62 6A  65 63 74 01 00 04 74 65
73 74 01 00 01 49 01 00  06 3C 69 6E 69 74 3E 01
00 03 28 29 56 01 00 04  43 6F 64 65 0A 00 03 00
0B 0C 00 07 00 08 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 07 4C  48 65 6C 6C 6F 3B 01 00
02 6D 79 01 00 03 28 29  49 09 00 01 00 13 0C 00
05 00 06 01 00 0A 53 6F  75 72 63 65 46 69 6C 65
01 00 0A 48 65 6C 6C 6F  2E 6A 61 76 61 00 21 00
01 00 03 00 00 00 01 00  02 00 05 00 06 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 0A B1 00 00 00 02
00 0C 00 00 00 06 00 01  00 00 00 03 00 0D 00 00
00 0C 00 01 00 00 00 05  00 0E 00 0F 00 00 00 01
00 10 00 11 00 01 00 09  00 00 00 2F 00 01 00 01
00 00 00 05 2A B4 00 12  AC 00 00 00 02 00 0C 00
00 00 06 00 01 00 00 00  06 00 0D 00 00 00 0C 00
01 00 00 00 05 00 0E 00  0F 00 00 00 01 00 14 00
00 00 02 00 15

  

cafebabe 魔数
00 00 00 34 JAVA 版本号
00 16 21个变量
1、07 00 02 Constant_Class_info 类或者符号的引用
Constant_Class_info{
  U1 tag 07
  U2 name_index 00 02 指向常量池中第二个class对象 hello
}
2、01 00 05 Constan_Utf8_Info utf-8的字符串编码
Constant_Utf8_info{
  U1 tag 01
  U2 length 00 05 说明有五个字节
  U1 byte 48 65 6C 6C 6F 换算后是Hello
}
3、07 00 04 Constant_Class_info 类或者符号的引用
Constant_Class_info{
  U1 tag 07
  U2 name_index 00 04 指向常量池中第四个class对象
}
4、01 00 10 Constan_Utf8_Info utf-8的字符串编码
Constant_Utf8_info{
  U1 tag 01
  U2 length 00 10 说明有16个字节
  U1 byte
  6A 61 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74 换算后是java/lang/Object
}
5、01 00 04 utf8 74 65 73 74 换算后 test
6、01 00 01 utf8 49换算后I
7、01 00 06 utf8 3C 69 6E 69 74 3E换算后<init>
8、01 00 03 utf8 28 29 56换算后()V
9、01 00 04 utf8 43 6F 64 65换算后Code
10、0A 00 03 00 0B Constant_Methodref_info
Constant_Methodref_info{
  U1 tag 0a
  U2 index 00 03 class_index 指向常量池中第3个常量所表示的类
  U2 index 00 0b name_and_type_index 指向常量池中第11个常量所表示的方法
}
11、0C 00 07 00 08 Constant_NameAndType_info
Constant_NameAndType_info
{
  u1 tag 0c
  u2 index 00 07 //指向常量池中第7个常量
  u2 index 00 08 //指向常量池中方法描述符号引用第8个描述
}
12、01 00 0F utf-8 4C 69 6E 65 4E 75 6D 62 65 72 54 61 62 6C 65 换算后LineNumberTable
13、01 00 12 utf8 4C 6F 63 61 6C 56 61 72 69 61 62 6C 65 54 61 62 6C 65 换算后 LocalVariableTable
14、01 00 04 utf8 74 68 69 73 换算后 this
15、01 00 07 utf8 4C 48 65 6C 6C 6F 3B 换算后LHello
16、01 00 02 utf8 6D 79 my //方法名
17、01 00 03 utf8 28 29 49换算后 ()I
18、09 00 01 00 13 Constant_Fieldref_info
Constant_Fieldref_info{
  U1 tag 09
  U2 index 00 01 //指向常量池中第1个class 的引用
  U2 index 00 13 //指向常量池中第19个常量所表示的变量
}
19、0C 00 05 00 06 Constant_NameAndType_info 指向常量池中第五个常量 指向常量池中方法描述符号引用第6个描述
20、01 00 0A utf8 53 6F 75 72 63 65 46 69 6C 65 换算后SourceFile
21、01 00 0A utf8 48 65 6C 6C 6F 2E 6A 61 76 61 00 21 00 换算后Hello.java

 javap 解析之后的信息 

 

 

 

00 21
00 21这两个字节的数据表示这个变量的访问标志位,JVM对访问标示符的规范如下:
00 21 = 00001 | 0020 表明此方法为public

 

 

类索引 U2(两个字节) 00 01 指向常量池中第一个类对象第二个类对象又指向常量池中第四个字符串常量即hello
  00 03指向常量池中第三个类对象第四个类对象又指向常量池中第四个字符串常量即java/lang/Object

  00 00 interface 为0个 没有继承接口

 

 

 


00 01 00 02 00 05 00 06 00 00字段集合
00 01 表明有一个字段
00 02 private
00 05 指向常量池中第五个字符串常量 –>test
00 06指向常量池中第六个字符串常量描述 I 为int 类型
00 00用来描述该变量的属性,因为这个变量没有附加属性,所以attributes_count为0,attribute_info为空。

 

方法集合
    00 02 表明有两个方法
    00 01 00 07 00 08
    00 01 方法描述 public
    00 07 方法名称在常量池中的位置 -> init
    00 08 方法描述在常量池中第八个位置->()V void类型
    00 01 说明有一个属性
  属性结构为 {
  U2 attribute_name_inde 00 09 Code
    Code 的结构为{
      u2 attribute_name_index;
      u4 attribute_length;
      u2 max_stack;
      u2 max_locals;
      u4 code_length;
      u1 code[code_length];
      u2 exception_table_length; //00 00 没有异常信息处理
        {
          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];
      }

 

 


code 为指令码操作的逻辑了 
attribute_length表示attribute所包含的字节数,这里为0000002f,即是39个字节,不包含attribute_name_index和attribute_length字段。
max_stack表示这个方法运行的任何时刻所能达到的操作数栈的最大深度,这里是0001
max_locals表示方法执行期间创建的局部变量的数目,包含用来表示传入的参数的局部变量,这里是0001.
接下来的code_length表示该方法的所包含的字节码的字节数以及具体的指令码。
这里的字节码长度为00000005,即是后面的5个字节 2a b7 00 01 b1为对应的字节码指令的指令码。
参照下表可以将上面的指令码翻译成对应的助记符:
  2a aload_0
  b7 invokespecial
  00 nop
  01 aconst_null
  b1 return
  U4 attribute_length
  U1 info
  
接下来是exception_table,这里存放的是处理异常的信息。
每个exception_table表项由start_pc,end_pc,handler_pc,catch_type组成。start_pc和end_pc表示在code数组中的从start_pc到end_pc处(包含start_pc,不包含end_pc)的指令抛出的异常会由这个表项来处理;handler_pc表示处理异常的代码的开始处。catch_type表示会被处理的异常类型,它指向常量池里的一个异常类。当catch_type为0时,表示处理所有的异常,这个可以用来实现finally的功能。

不过,这段代码里没有异常处理,所以exception_table_length为0000

  LineNumberTable_attribute {
    u2 attribute_name_index; 00 0c linNumberTable
    u4 attribute_length; 00 00 00 06 6个长度
    u2 line_number_table_length; 00 01
    {

       u2 start_pc; 00 00
      u2 line_number; 00 03 表示从第0行的第三个字节码开始

    } line_number_table[line_number_table_length];
   } 

 

 
第二个方法以此类推

 

 

 

attributes
最后剩下的内容是attributes,这里的attributes表示整个class文件的附加属性,不过结构还是和前面的attribute保持一致。00 01表示有一个attribute。
Attribute结构如下:

SourceFile_attribute {
  u2 attribute_name_index;
  u4 attribute_length;
  u2 sourcefile_index;
  }
  attribute_name_index为0014,指向第20个常量,为SourceFile,说明这个属性是Source
  attribute_length为00000002
  sourcefile_index为0015,表示指向常量池里的第21个常量,为Hello.java。
  这个属性表明当前的class文件是从Hello.java文件编译而来。

 

 

                                            参考文档地址 :https://blog.csdn.net/weelyy/article/details/78969412

 

posted @ 2019-03-18 18:45  王南辉  阅读(669)  评论(0编辑  收藏  举报