转载

空手套白狼,硬阅java字节码class文件

如下,是一些java字节码也就是原始的class文件,当应用部署到线上之后,我们能够看到的也就是这样的字样了。那么怎样解呢?就让我们一起,来解读解读字节码吧!

Offset      0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F

00000000   CA FE BA BE 00 00 00 34  00 6A 0A 00 1C 00 39 0A   漱壕   4 j    9 
00000010   00 13 00 3A 09 00 13 00  3B 09 00 3C 00 3D 08 00      :    ;  < =  
00000020   3E 0A 00 3F 00 40 07 00  41 0A 00 07 00 39 09 00   >  ? @  A    9  
00000030   13 00 42 07 00 43 0A 00  0A 00 39 08 00 44 0A 00     B  C    9  D  
00000040   0A 00 45 0A 00 46 00 47  0A 00 0A 00 48 08 00 49     E  F G    H  I
00000050   0A 00 0A 00 4A 0B 00 4B  00 4C 07 00 4D 0A 00 13       J  K L  M   
00000060   00 39 0A 00 13 00 4E 07  00 4F 0A 00 16 00 39 08    9    N  O    9 
00000070   00 50 0A 00 16 00 51 0A  00 16 00 52 0A 00 16 00    P    Q    R    
00000080   53 07 00 54 01 00 0B 75  73 65 72 53 65 72 76 69   S  T   userServi
00000090   63 65 01 00 24 4C 63 6F  6D 2F 79 6F 75 67 65 2F   ce  $Lcom/youge/
000000A0   73 65 72 76 69 63 65 2F  75 73 65 72 2F 55 73 65   service/user/Use
000000B0   72 53 65 72 76 69 63 65  3B 01 00 09 69 6E 69 74   rService;   init
000000C0   69 61 6C 65 64 01 00 01  5A 01 00 06 3C 69 6E 69   ialed   Z   <ini
000000D0   74 3E 01 00 03 28 29 56  01 00 04 43 6F 64 65 01   t>   ()V   Code 

0. class文件的整体格式

type    descriptor    remark

u4      magic   0xCAFEBABE

u2      minor_version

u2      major_version

u2      constant_pool_count

cp_info   constant_pool[cosntant_pool_count – 1]index 0 is invalid

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]

1. 文件头

CA FE BA BE: 前四个字节,魔数,代表文件类型,java的class文件固定为 0xCAFEBABE. 助记词: 咖啡宝贝

00 00 00 34: 接下来要知道版本号。版本号含主版本号和次版本号,都是各占2个字节。在此Demo种为0X0000 0034。其中前面的0000是次版本号,后面的0034是主版本号。通过进制转换得到的是次版本号为0,主版本号为52。

从oracle官方网站我们能够知道,52对应的正式jdk1.8,而其次版本为0,所以该文件的版本为1.8.0。如果需要验证,可以在用java –version命令输出版本号,或者修改编译目标版本–target重新编译,查看编译后的字节码文件版本号是否做了相应的修改。

2. 常量池

至此,我们共了解了前8字节的含义,下面讲讲常量池相关内容。

紧接着主版本号之后的就是常量池入口。常量池是Class文件中的资源仓库,在接下来的内容中我们会发现很多地方会涉及,如Class Name,Interfaces等。常量池中主要存储2大类常量:字面量和符号引用。字面量如文本字符串,java中声明为final的常量值等等,而符号引用如类和接口的全局限定名,字段的名称和描述符,方法的名称和描述符。

为什么需要类和接口的全局限定名呢?系统引用类或者接口的时候不是通过内存地址进行操作吗?这里大家仔细想想,java虚拟机在没有将类加载到内存的时候根本都没有分配内存地址,也就不存在对内存的操作,所以java虚拟机首先需要将类加载到虚拟机中,那么这个过程设计对类的定位(需要加载A包下的B类,不能加载到别的包下面的别的类中),所以需要通过全局限定名来判别唯一性。这就是为什么叫做全局,限定的意思,也就是唯一性。

在进行具体常量池分析之前,我们先来了解一下常量池的项目类型表:

这里tag用来表示当前常量池不同类型的项。info中存放常量池项中存放的数据。

tag中表示的数据类型:

tag名称remark

CONSTANT_Class_info   用于记录类或接口名

CONSTANT_Integer_info 用于记录int类型的常量值

CONSTANT_Long_info    用于记录long类型的常量值

CONSTANT_Float_info    用于记录float类型的常量值

CONSTANT_Double_info  用于记录double类型的常量值

CONSTANT_String_info用于记录常量字符串的值

CONSTANT_Fieldref_info    用于记录字段信息(包括类或接口中定义的字段以及代码中使用到的字段)

CONSTANT_Methodref_info    用于记录方法信息(包括类中定义的方法以及代码中使用到的方法)

CONSTANT_InterfaceMethodref_info   用于记录接口中的方法信息(包括接口中定义的方法以及代码中使用到的方法)

CONSTANT_NameAndType_info 记录方法或字段的名称(name)和描述符(descriptor)

CONSTANT_Utf8_info   记录字符串的值

上面的表中描述了11中数据类型的结构,其实在jdk1.7之后又增加了3种( CONSTANT_MethodHandle_info ,CONSTANT_MethodType_info 以及 CONSTANT_InvokeDynamic_info )。这样算起来一共是14种。接下来我们按照Demo的字节码进行逐一翻译。

0x006A: 由于常量池的数量不固定(n+2),所以需要在常量池的入口处放置一项u2类型的数据代表常量池数量。因此该6A进制是106,表示有105项常量,索引范围为1~105。Class文件格式规定,设计者就讲第0项保留出来了,以备后患。从这里我们知道接下来我们需要翻译出105项常量。

Constant #1 (一共有105个常量,这是第一个,以此类推…)

0x0A:从常量类型表中我们发现,第一个数据均是u1类型的tag,16进制的0a是十进制的10,对应表中的MethodRef_info。

0x001C: 指向方法描述符 CONSTANT_Class_info 的索引项, 为 #28, 查找得: #84           // java/lang/Object

0x0039: 指向名称及类型描述符 CONSTANT_NameAndType_info 的索引项, 为 #57, 查找得 #33:#34       // "<init>":()V

如上,依次计算出每个常量池的范围,直到 105项全部计算完成。

3 Access_Flag 访问标志

类或接口的访问权限

Flag NameValueRemarks

ACC_PUBLIC0x0001pubilc,包外可访问。

ACC_FINAL0x0010final,不能有子类。

ACC_SUPER0x0020用于兼容早期编译器,新编译器都设置该标记,以在使用 invokespecial指令时对子类方法做特定处理。

ACC_INTERFACE0x0200接口,同时需要设置:ACC_ABSTRACT。不可同时设置:ACC_FINAL、ACC_SUPER、ACC_ENUM

ACC_ABSTRACT0x0400抽象类,无法实例化。不可和ACC_FINAL同时设置。

ACC_SYNTHETIC 0x1000synthetic,由编译器产生,不存在于源代码中。 ACC_ANNOTATION 0x2000注解类型(annotation),需同时设置:ACC_INTERFACE、ACC_ABSTRACT

ACC_ENUM0x4000枚举类型

访问标志信息包括该Class文件是类还是接口,是否被定义成public,是否是abstract,如果是类,是否被声明成final。通过上面的源代码,我们知道该文件是类并且是public。

4  this_class

0x0013: this_class是指向constant pool的索引值,该值必须是CONSTANT_Class_info类型,指定当前字节码定义的类或接口。

5 父类索引 super_class

0x001C: 同理:#28(Class #84 java/lang/Object)

6 接口索引 interfaces

0x0000: 通过java_byte.jpeg图我们知道,这个接口有2+n个字节,前两个字节表示的是接口数量,后面跟着就是接口的表。偏移量为: 4(magic)+4(version)+2+106*(constant)+2(access_flags)+2(this)+2(super)=122*,我们这个类没有任何接口,所以应该是0000。常量池是动态变化的,有点难算,不过算出来就是这个值。此处可以先找到super

7 字段表集合

字段表用于描述类和接口中声明的变量。这里的字段包含了类级别变量以及实例变量,但是不包括方法内部声明的局部变量。

同样,接下来就是2+n个字段属性。我们只有一个属性a,按道理应该是0001。查找文件果不其然是0001。

那么接下来我们要针对这样的字段进行解析。附上字段表如下:

typedescriptorremark

u2access_flags记录字段的访问权限。

u2name_indexconstant_pool中的索引,CONSTANT_Utf8_info类型。指定字段的名称。

u2descriptor_indexconstant_pool中的索引,CONSTANT_Utf8_info类型,指定字段的描述符(见附录C)。

u2attributes_countattributes包含的项目数。

attribute_infoattributes[attributes_count]

0x00 02: 访问标志为private(自行搜索字段访问标志)

0x00 02: 字段名称索引为#2,对应的是 Methodref          #19.#58       // com/youge/api/ByteCodeClassKen.init:()V

0x001D: 描述符索引为#29,对应的是 Utf8 userService

0x001E :描述符索引为#30,对应的是 Utf8 Lcom/youge/service/user/UserService;

0x00 00 :属性表数量为0,因此没有属性表。

8 方法

我们只有一个方法testMethod,按照道理应该前2个字节是0001。通过查找发现是0x00 02。这是什么原因,这代表着有2个方法呢?且继续看……

上图是一张方法表结构图,按照这个图我们分析下面的字节码:

typedescriptorremark

u2access_flags记录方法的访问权限。见2.9.1

u2name_indexconstant_pool中的索引,CONSTANT_Utf8_info类型。指定方法名称。

u2descriptor_indexconstant_pool中的索引,CONSTANT_Utf8_info类型,指定方法的描述符(见附录C)。

u2attributes_countattributes包含的项目数。

attribute_infoattributes[attributes_count]字段中包含的Attribute集合。见2.9.2-2.9.11

第1个方法:

0x00 01:访问标志 ACC_PUBLIC,表明该方法是public。(可自行搜索方法访问标志表)

0x00 07:方法名索引为#7,对应的是"<init>"

0x00 08:方法描述符索引为#8,对应的是"()V"

0x00 01:属性表数量为1(一个属性表)

那么这里涉及到了属性表。什么是属性表呢?可以这么理解,它是为了描述一些专有信息的,上面的方法带有一张属性表。所有属性表的结构如下图:

一个u2的属性名称索引,一个u2的属性长度加上属性长度的info。

虚拟机规范预定义的属性有很多,比如Code,LineNumberTable,LocalVariableTable,SourceFile等等,这个网上可以搜索到。

按照上面的表结构解析得到下面信息:

Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15


00001344   00 23 00 00 00 3B 00 01  00 01 00 00 00 09 2A B7    #   ;        *?

00001360   00 01 2A B7 00 02 B1 00  00 00 02 00 24 00 00 00     *? ?    $   

00001376   0E 00 03 00 00 00 12 00  04 00 13 00 08 00 14 00                   

00001392   25 00 00 00 0C 00 01 00  00 00 09 00 26 00 27 00   %           & ' 

00001408   00 00 02 00 28 00 22 00  01 00 23 00 00 00 63 00       ( "   #   c 

00001424   03 00 01 00 00 00 20 2A  B4 00 03 9A 00 1B B2 00          *? ? ?

00001440   04 12 05 B6 00 06 2A BB  00 07 59 B7 00 08 B5 00      ? *? Y? ?

00001456   09 2A 04 B5 00 03 B1 00  00 00 03 00 24 00 00 00    * ? ?    $   

00001472   16 00 05 00 00 00 17 00  07 00 18 00 0F 00 19 00                   

00001488   1A 00 1A 00 1F 00 1C 00  25 00 00 00 0C 00 01 00           %       

00001504   00 00 20 00 26 00 27 00  00 00 29 00 00 00 03 00       & '   )     

00001520   01 1F 00 01 00 2A 00 2B  00 02 00 23 00 00 00 6C        * +   #   l

00001536   00 02 00 02 00 00 00 28  BB 00 0A 59 B7 00 0B 4C          (? Y? L

00001552   2B 12 0C B6 00 0D 2B 10  0C B8 00 0E B6 00 0F 2B   +  ? +  ? ? +

00001568   12 10 B6 00 11 2A B4 00  09 2B B9 00 12 02 00 B0     ? *? +?   ?

0x0023:名称索引为#35("Code")。

0x0000 003B: 属性长度为59字节。

那么接下来解析一个Code属性表,按照下图解析

Code Attribute

typedescriptorremark

u2attribute_name_indexconstant_pool中的索引,CONSTANT_Utf8_info类型。指定Attribute的名称("Code")。

u4attribute_length该Attribute内容的字节长度。

u2max_stack该方法操作栈的最大深度。

u2max_locals该方法调用时需要分配的局部变量的最大个数,包括该方法的参数。

u4code_length该方法字节码长度(以字节为单位)

u1code[code_length]存放字节码数组(字节码如何解析?)。

u2exception_table_length异常表的长度。

exception_table_info每个表项记录一段异常处理代码信息和范围。

u2start_pc记录应用该项异常处理的起始字节码。在字节码数组中的起始索引号[start_pc, end_pc)。索引号必须是opcode(一条指令的开始位置)对应的位置。

u2end_pcu2

handler_pc记录该项异常处理代码的开始地址。在字节码数组中的开始索引号。索引号必须是opcode对应的位置。

u2catch_typeconstant_pool中的索引,CONSTANT_Class_info类型。指定该项能捕获的异常类(或其子类)。或0用于实现finally语法(即不管什么类型都会捕获。)

exception_table[exception_table_length]

u2attributes_countattributes包含的项目数。

attribute_infoattributes[attributes_count]

xxx

前面6个字节(名称索引2字节+属性长度4字节)已经解析过了,所以接下来就是解析剩下的59-6=53字节即可。

0x00 01: max_stack=1

0x00 01: max_locals=1

0x0000 0009: code_length=9

0x2A B7 00 01 2A B7 00 02 B1: 这是code代码,可以通过虚拟机字节码指令进行查找。

2a=aload_0(将第一个引用变量推送到栈顶)

b7=invokespecial(调用父类构造方法)

00=什么都不做

01=将 #1 常量池推送到栈顶,即默认"<init>":()V 构造方法

2a=同上

b7=同上

00=什么都不做

02=将#2常量池推送栈顶,即 init() 方法

b1=return 从当前方法返回void

整理,去除无动作指令得到下面

0: aload_0

1: invokespecial #1                  // Method java/lang/Object."<init>":()V

4: aload_0

5: invokespecial #2                  // Method init:()V

8: return

接下来顺着Code属性表继续解析下去:

0x00 00 : exception_table_length=0

0x00 02 : attributes_count=2(Code属性表内部还含有2个属性表)

0x00 24: 第一个属性表是"LineNumberTable"

0x00 00 00 0E : "属性长度为14″

0x00 03 :line_number_table_length=3

line_number_table是一个数量为line_number_table_length,类型为line_number_info的集合,line_number_info表包括了start_pc和line_number两个u2类型的数据项,前者是字节码行号,后者是Java源码行号

0x00 00 : start_pc=0

0x00 12 : end_pc=18

0x00 04 : start_pc=4

0x00 13 : end_pc=19

0x00 25 第二个属性表是:"LocalVariableTable"

0x00 0000 0c:属性长度为12

0x00 01 : local_variable_table_length=1

然后按照local_variable_info表结构进行解析:

0x00 00 : start_pc=0

0x00 09:length=9

0x0026 : #38 name_index="this"

0x0027 : #39 descriptor_index #13 ("Lcom/youge/api/ByteCodeClassKen;")

0000 index=0

-----------到这里第一个方法就解析完成了--------------------

Method(<init>)–1个属性Code表-2个属性表(LineNumberTable ,LocalVariableTable)

10 Attribute

attributes数组记录了和类或接口相关的所有Attribute项(和字段相关的Attribute在field_info的attributes中,和方法相关的Attribute在method_info的attrubutes中,和字节码相关的Attribute在Code Attribute的attributes中)。attributes数组中的每项都是attribute_info类型,它描述了Attribute的名称、详细信息等。该attributes数组描述了ClassFile的一些额外信息。JVM必须忽略它不能识别的Attribute,而且那些JVM不能识别的的Attribute也不能影响class文件的语义。

当前定义的Attribute有:Code Attribute、Constant Value Attibute、Deprecated Attribute、Enclosing Method Attribute、Exceptions Attribute、Inner Classes Attribute、Line Number Table Attribute、Local Variable Table Attribute、Local Variable Type Table Attribute、Runtime Visible Annotations Attribute、Runtime Invisible Annotation Attribute、Runtime Visible Parameter Annotation Attribute、Runtime Invisible Parameter Annotation Attribute、Signature Attribute、Source Debug Extension Attribute、Source File Attribute、Stack Map Table Attribute、Synthetic Attribute、Annotation Default Attribute等。它们有些只存在于field_info中,有些只存在method_info中,有些只存在ClassFile中,有些只存在于Code Attribute中,还有些可以同时存在于field_info、method_info、classfile中。

Attribute结构只存在与ClassFile、method_info、field_info、Code Attribute结构中。

0x0002 :同样的,表示有2个Attributes了。

0x0037 : #15("SourceFile")

0x0000 0002 attribute_length=2

0x0038 : sourcefile_index = #56("ByteCodeClassKen.java")

SourceFile属性用来记录生成该Class文件的源码文件名称。

11. 直接使用 javap 反编译成可读的文本型字节码

javap -verbose xxx.class

Classfile /D:/www/test/target/classes/com/youge/api/ByteCodeClassKen.class
  Last modified 2018-9-26; size 1801 bytes
  MD5 checksum 76e207e502c3b096346480457d98cdef
  Compiled from "ByteCodeClassKen.java"
public class com.youge.api.ByteCodeClassKen
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
    #1 = Methodref          #28.#57       // java/lang/Object."<init>":()V
    #2 = Methodref          #19.#58       // com/youge/api/ByteCodeClassKen.init:()V
    #3 = Fieldref           #19.#59       // com/youge/api/ByteCodeClassKen.initialed:Z
    #4 = Fieldref           #60.#61       // java/lang/System.out:Ljava/io/PrintStream;
    #5 = String             #62           // init...
    #6 = Methodref          #63.#64       // java/io/PrintStream.println:(Ljava/lang/String;)V
    #7 = Class              #65           // com/youge/service/user/UserServiceImpl
    #8 = Methodref          #7.#57        // com/youge/service/user/UserServiceImpl."<init>":()V
    #9 = Fieldref           #19.#66       // com/youge/api/ByteCodeClassKen.userService:Lcom/youge/service/user/UserService;
   #10 = Class              #67           // com/youge/pojo/user/UserInfo
   #11 = Methodref          #10.#57       // com/youge/pojo/user/UserInfo."<init>":()V
   #12 = String             #68           // lilei
   #13 = Methodref          #10.#69       // com/youge/pojo/user/UserInfo.setName:(Ljava/lang/String;)V
   #14 = Methodref          #70.#71       // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   #15 = Methodref          #10.#72       // com/youge/pojo/user/UserInfo.setAge:(Ljava/lang/Integer;)V
   #16 = String             #73           // new road.
   #17 = Methodref          #10.#74       // com/youge/pojo/user/UserInfo.setAddress:(Ljava/lang/String;)V
   #18 = InterfaceMethodref #75.#76       // com/youge/service/user/UserService.addUser:(Lcom/youge/pojo/user/UserInfo;)Ljava/lang/Integer;
   #19 = Class              #77           // com/youge/api/ByteCodeClassKen
   #20 = Methodref          #19.#57       // com/youge/api/ByteCodeClassKen."<init>":()V
   #21 = Methodref          #19.#78       // com/youge/api/ByteCodeClassKen.addUser:()Ljava/lang/Integer;
   #22 = Class              #79           // java/lang/StringBuilder
   #23 = Methodref          #22.#57       // java/lang/StringBuilder."<init>":()V
   #24 = String             #80           // affect:
   #25 = Methodref          #22.#81       // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   #26 = Methodref          #22.#82       // java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
   #27 = Methodref          #22.#83       // java/lang/StringBuilder.toString:()Ljava/lang/String;
   #28 = Class              #84           // java/lang/Object
   #29 = Utf8               userService
   #30 = Utf8               Lcom/youge/service/user/UserService;
   #31 = Utf8               initialed
   #32 = Utf8               Z
   #33 = Utf8               <init>
   #34 = Utf8               ()V
   #35 = Utf8               Code
   #36 = Utf8               LineNumberTable
   #37 = Utf8               LocalVariableTable
   #38 = Utf8               this
   #39 = Utf8               Lcom/youge/api/ByteCodeClassKen;
   #40 = Utf8               init
   #41 = Utf8               StackMapTable
   #42 = Utf8               addUser
   #43 = Utf8               ()Ljava/lang/Integer;
   #44 = Utf8               userInfo
   #45 = Utf8               Lcom/youge/pojo/user/UserInfo;
   #46 = Utf8               Exceptions
   #47 = Class              #85           // java/lang/Exception
   #48 = Utf8               main
   #49 = Utf8               ([Ljava/lang/String;)V
   #50 = Utf8               args
   #51 = Utf8               [Ljava/lang/String;
   #52 = Utf8               classKen
   #53 = Utf8               affect
   #54 = Utf8               Ljava/lang/Integer;
   #55 = Utf8               SourceFile
   #56 = Utf8               ByteCodeClassKen.java
   #57 = NameAndType        #33:#34       // "<init>":()V
   #58 = NameAndType        #40:#34       // init:()V
   #59 = NameAndType        #31:#32       // initialed:Z
   #60 = Class              #86           // java/lang/System
   #61 = NameAndType        #87:#88       // out:Ljava/io/PrintStream;
   #62 = Utf8               init...
   #63 = Class              #89           // java/io/PrintStream
   #64 = NameAndType        #90:#91       // println:(Ljava/lang/String;)V
   #65 = Utf8               com/youge/service/user/UserServiceImpl
   #66 = NameAndType        #29:#30       // userService:Lcom/youge/service/user/UserService;
   #67 = Utf8               com/youge/pojo/user/UserInfo
   #68 = Utf8               lilei
   #69 = NameAndType        #92:#91       // setName:(Ljava/lang/String;)V
   #70 = Class              #93           // java/lang/Integer
   #71 = NameAndType        #94:#95       // valueOf:(I)Ljava/lang/Integer;
   #72 = NameAndType        #96:#97       // setAge:(Ljava/lang/Integer;)V
   #73 = Utf8               new road.
   #74 = NameAndType        #98:#91       // setAddress:(Ljava/lang/String;)V
   #75 = Class              #99           // com/youge/service/user/UserService
   #76 = NameAndType        #42:#100      // addUser:(Lcom/youge/pojo/user/UserInfo;)Ljava/lang/Integer;
   #77 = Utf8               com/youge/api/ByteCodeClassKen
   #78 = NameAndType        #42:#43       // addUser:()Ljava/lang/Integer;
   #79 = Utf8               java/lang/StringBuilder
   #80 = Utf8               affect:
   #81 = NameAndType        #101:#102     // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   #82 = NameAndType        #101:#103     // append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
   #83 = NameAndType        #104:#105     // toString:()Ljava/lang/String;
   #84 = Utf8               java/lang/Object
   #85 = Utf8               java/lang/Exception
   #86 = Utf8               java/lang/System
   #87 = Utf8               out
   #88 = Utf8               Ljava/io/PrintStream;
   #89 = Utf8               java/io/PrintStream
   #90 = Utf8               println
   #91 = Utf8               (Ljava/lang/String;)V
   #92 = Utf8               setName
   #93 = Utf8               java/lang/Integer
   #94 = Utf8               valueOf
   #95 = Utf8               (I)Ljava/lang/Integer;
   #96 = Utf8               setAge
   #97 = Utf8               (Ljava/lang/Integer;)V
   #98 = Utf8               setAddress
   #99 = Utf8               com/youge/service/user/UserService
  #100 = Utf8               (Lcom/youge/pojo/user/UserInfo;)Ljava/lang/Integer;
  #101 = Utf8               append
  #102 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;
  #103 = Utf8               (Ljava/lang/Object;)Ljava/lang/StringBuilder;
  #104 = Utf8               toString
  #105 = Utf8               ()Ljava/lang/String;
{
  public com.youge.api.ByteCodeClassKen();
    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: aload_0
         5: invokespecial #2                  // Method init:()V
         8: return
      LineNumberTable:
        line 18: 0
        line 19: 4
        line 20: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  this   Lcom/youge/api/ByteCodeClassKen;

  public java.lang.Integer addUser() throws java.lang.Exception;
    descriptor: ()Ljava/lang/Integer;
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=1
         0: new           #10                 // class com/youge/pojo/user/UserInfo
         3: dup
         4: invokespecial #11                 // Method com/youge/pojo/user/UserInfo."<init>":()V
         7: astore_1
         8: aload_1
         9: ldc           #12                 // String lilei
        11: invokevirtual #13                 // Method com/youge/pojo/user/UserInfo.setName:(Ljava/lang/String;)V
        14: aload_1
        15: bipush        12
        17: invokestatic  #14                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        20: invokevirtual #15                 // Method com/youge/pojo/user/UserInfo.setAge:(Ljava/lang/Integer;)V
        23: aload_1
        24: ldc           #16                 // String new road.
        26: invokevirtual #17                 // Method com/youge/pojo/user/UserInfo.setAddress:(Ljava/lang/String;)V
        29: aload_0
        30: getfield      #9                  // Field userService:Lcom/youge/service/user/UserService;
        33: aload_1
        34: invokeinterface #18,  2           // InterfaceMethod com/youge/service/user/UserService.addUser:(Lcom/youge/pojo/user/UserInfo;)Ljava/lang/Integer;
        39: areturn
      LineNumberTable:
        line 31: 0
        line 32: 8
        line 33: 14
        line 34: 23
        line 35: 29
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      40     0  this   Lcom/youge/api/ByteCodeClassKen;
            8      32     1 userInfo   Lcom/youge/pojo/user/UserInfo;
    Exceptions:
      throws java.lang.Exception

  public static void main(java.lang.String[]) throws java.lang.Exception;
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=3, args_size=1
         0: new           #19                 // class com/youge/api/ByteCodeClassKen
         3: dup
         4: invokespecial #20                 // Method "<init>":()V
         7: astore_1
         8: aload_1
         9: invokevirtual #21                 // Method addUser:()Ljava/lang/Integer;
        12: astore_2
        13: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
        16: new           #22                 // class java/lang/StringBuilder
        19: dup
        20: invokespecial #23                 // Method java/lang/StringBuilder."<init>":()V
        23: ldc           #24                 // String affect:
        25: invokevirtual #25                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        28: aload_2
        29: invokevirtual #26                 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
        32: invokevirtual #27                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        35: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        38: return
      LineNumberTable:
        line 40: 0
        line 41: 8
        line 42: 13
        line 43: 38
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      39     0  args   [Ljava/lang/String;
            8      31     1 classKen   Lcom/youge/api/ByteCodeClassKen;
           13      26     2 affect   Ljava/lang/Integer;
    Exceptions:
      throws java.lang.Exception
}
SourceFile: "ByteCodeClassKen.java"

Offset      0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F

00000000   CA FE BA BE 00 00 00 34  00 6A 0A 00 1C 00 39 0A   漱壕   4 j    9 00000010   00 13 00 3A 09 00 13 00  3B 09 00 3C 00 3D 08 00      :    ;  < =  00000020   3E 0A 00 3F 00 40 07 00  41 0A 00 07 00 39 09 00   >  ? @  A    9  00000030   13 00 42 07 00 43 0A 00  0A 00 39 08 00 44 0A 00     B  C    9  D  00000040   0A 00 45 0A 00 46 00 47  0A 00 0A 00 48 08 00 49     E  F G    H  I00000050   0A 00 0A 00 4A 0B 00 4B  00 4C 07 00 4D 0A 00 13       J  K L  M   00000060   00 39 0A 00 13 00 4E 07  00 4F 0A 00 16 00 39 08    9    N  O    9 00000070   00 50 0A 00 16 00 51 0A  00 16 00 52 0A 00 16 00    P    Q    R    00000080   53 07 00 54 01 00 0B 75  73 65 72 53 65 72 76 69   S  T   userServi00000090   63 65 01 00 24 4C 63 6F  6D 2F 79 6F 75 67 65 2F   ce  $Lcom/youge/000000A0   73 65 72 76 69 63 65 2F  75 73 65 72 2F 55 73 65   service/user/Use000000B0   72 53 65 72 76 69 63 65  3B 01 00 09 69 6E 69 74   rService;   init000000C0   69 61 6C 65 64 01 00 01  5A 01 00 06 3C 69 6E 69   ialed   Z   <ini000000D0   74 3E 01 00 03 28 29 56  01 00 04 43 6F 64 65 01   t>   ()V   Code 

如上,是一些java字节码也就是原始的class文件,当应用部署到线上之后,我们能够看到的也就是这样的字样了。那么怎样解呢?

0. class文件的整体格式typedescriptorremarku4magic0xCAFEBABEu2minor_versionu2major_versionu2constant_pool_countcp_infoconstant_pool[cosntant_pool_count – 1]index 0 is invalidu2access_flagsu2this_classu2super_classu2interfaces_countu2interfaces[interfaces_count]u2fields_countfield_infofields[fields_count]u2methods_countmethod_infomethods[methods_count]u2attributes_countattribute_infoattributes[attributes_count]

1. 文件头CA FE BA BE: 前四个字节,魔数,代表文件类型,java的class文件固定为 0xCAFEBABE. 助记词: 咖啡宝贝00 00 00 34: 接下来要知道版本号。版本号含主版本号和次版本号,都是各占2个字节。在此Demo种为0X0000 0034。其中前面的0000是次版本号,后面的0034是主版本号。通过进制转换得到的是次版本号为0,主版本号为52。从oracle官方网站我们能够知道,52对应的正式jdk1.8,而其次版本为0,所以该文件的版本为1.8.0。如果需要验证,可以在用java –version命令输出版本号,或者修改编译目标版本–target重新编译,查看编译后的字节码文件版本号是否做了相应的修改。

2. 常量池至此,我们共了解了前8字节的含义,下面讲讲常量池相关内容。紧接着主版本号之后的就是常量池入口。常量池是Class文件中的资源仓库,在接下来的内容中我们会发现很多地方会涉及,如Class Name,Interfaces等。常量池中主要存储2大类常量:字面量和符号引用。字面量如文本字符串,java中声明为final的常量值等等,而符号引用如类和接口的全局限定名,字段的名称和描述符,方法的名称和描述符。为什么需要类和接口的全局限定名呢?系统引用类或者接口的时候不是通过内存地址进行操作吗?这里大家仔细想想,java虚拟机在没有将类加载到内存的时候根本都没有分配内存地址,也就不存在对内存的操作,所以java虚拟机首先需要将类加载到虚拟机中,那么这个过程设计对类的定位(需要加载A包下的B类,不能加载到别的包下面的别的类中),所以需要通过全局限定名来判别唯一性。这就是为什么叫做全局,限定的意思,也就是唯一性。

在进行具体常量池分析之前,我们先来了解一下常量池的项目类型表:这里tag用来表示当前常量池不同类型的项。info中存放常量池项中存放的数据。

tag中表示的数据类型:tag名称remarkCONSTANT_Class_info用于记录类或接口名CONSTANT_Integer_info 用于记录int类型的常量值CONSTANT_Long_info用于记录long类型的常量值CONSTANT_Float_info用于记录float类型的常量值CONSTANT_Double_info用于记录double类型的常量值CONSTANT_String_info用于记录常量字符串的值CONSTANT_Fieldref_info用于记录字段信息(包括类或接口中定义的字段以及代码中使用到的字段)CONSTANT_Methodref_info用于记录方法信息(包括类中定义的方法以及代码中使用到的方法)CONSTANT_InterfaceMethodref_info用于记录接口中的方法信息(包括接口中定义的方法以及代码中使用到的方法)CONSTANT_NameAndType_info 记录方法或字段的名称(name)和描述符(descriptor)CONSTANT_Utf8_info记录字符串的值

上面的表中描述了11中数据类型的结构,其实在jdk1.7之后又增加了3种( CONSTANT_MethodHandle_info ,CONSTANT_MethodType_info 以及 CONSTANT_InvokeDynamic_info )。这样算起来一共是14种。接下来我们按照Demo的字节码进行逐一翻译。0x006A: 由于常量池的数量不固定(n+2),所以需要在常量池的入口处放置一项u2类型的数据代表常量池数量。因此该6A进制是106,表示有105项常量,索引范围为1~105。Class文件格式规定,设计者就讲第0项保留出来了,以备后患。从这里我们知道接下来我们需要翻译出105项常量。Constant #1 (一共有105个常量,这是第一个,以此类推…)0x0A:从常量类型表中我们发现,第一个数据均是u1类型的tag,16进制的0a是十进制的10,对应表中的MethodRef_info。0x001C: 指向方法描述符 CONSTANT_Class_info 的索引项, 为 #28, 查找得: #84           // java/lang/Object0x0039: 指向名称及类型描述符 CONSTANT_NameAndType_info 的索引项, 为 #57, 查找得 #33:#34       // "<init>":()V如上,依次计算出每个常量池的范围,直到 105项全部计算完成。

3.4 Access_Flag 访问标志

类或接口的访问权限Flag NameValueRemarksACC_PUBLIC0x0001pubilc,包外可访问。ACC_FINAL0x0010final,不能有子类。ACC_SUPER0x0020用于兼容早期编译器,新编译器都设置该标记,以在使用 invokespecial指令时对子类方法做特定处理。ACC_INTERFACE0x0200接口,同时需要设置:ACC_ABSTRACT。不可同时设置:ACC_FINAL、ACC_SUPER、ACC_ENUMACC_ABSTRACT0x0400抽象类,无法实例化。不可和ACC_FINAL同时设置。ACC_SYNTHETIC 0x1000synthetic,由编译器产生,不存在于源代码中。 ACC_ANNOTATION 0x2000注解类型(annotation),需同时设置:ACC_INTERFACE、ACC_ABSTRACTACC_ENUM0x4000枚举类型

访问标志信息包括该Class文件是类还是接口,是否被定义成public,是否是abstract,如果是类,是否被声明成final。通过上面的源代码,我们知道该文件是类并且是public。

3.5  this_class0x0013: this_class是指向constant pool的索引值,该值必须是CONSTANT_Class_info类型,指定当前字节码定义的类或接口。 

3.6父类索引 super_class0x001C: 同理:#28(Class #84 java/lang/Object)

3.7 接口索引 interfaces0x0000: 通过java_byte.jpeg图我们知道,这个接口有2+n个字节,前两个字节表示的是接口数量,后面跟着就是接口的表。偏移量为: 4(magic)+4(version)+2+106*(constant)+2(access_flags)+2(this)+2(super)=122*,我们这个类没有任何接口,所以应该是0000。常量池是动态变化的,有点难算,不过算出来就是这个值。此处可以先找到super

3.8 字段表集合字段表用于描述类和接口中声明的变量。这里的字段包含了类级别变量以及实例变量,但是不包括方法内部声明的局部变量。同样,接下来就是2+n个字段属性。我们只有一个属性a,按道理应该是0001。查找文件果不其然是0001。那么接下来我们要针对这样的字段进行解析。附上字段表如下:

typedescriptorremarku2access_flags记录字段的访问权限。u2name_indexconstant_pool中的索引,CONSTANT_Utf8_info类型。指定字段的名称。u2descriptor_indexconstant_pool中的索引,CONSTANT_Utf8_info类型,指定字段的描述符(见附录C)。u2attributes_countattributes包含的项目数。attribute_infoattributes[attributes_count]

0x00 02: 访问标志为private(自行搜索字段访问标志)0x00 02: 字段名称索引为#2,对应的是 Methodref          #19.#58       // com/youge/api/ByteCodeClassKen.init:()V0x001D: 描述符索引为#29,对应的是 Utf8 userService0x001E :描述符索引为#30,对应的是 Utf8 Lcom/youge/service/user/UserService;0x00 00 :属性表数量为0,因此没有属性表。

3.9 方法我们只有一个方法testMethod,按照道理应该前2个字节是0001。通过查找发现是0x00 02。这是什么原因,这代表着有2个方法呢?且继续看……上图是一张方法表结构图,按照这个图我们分析下面的字节码:

typedescriptorremarku2access_flags记录方法的访问权限。见2.9.1u2name_indexconstant_pool中的索引,CONSTANT_Utf8_info类型。指定方法名称。u2descriptor_indexconstant_pool中的索引,CONSTANT_Utf8_info类型,指定方法的描述符(见附录C)。u2attributes_countattributes包含的项目数。attribute_infoattributes[attributes_count]字段中包含的Attribute集合。见2.9.2-2.9.11

第1个方法:0x00 01:访问标志 ACC_PUBLIC,表明该方法是public。(可自行搜索方法访问标志表)0x00 07:方法名索引为#7,对应的是"<init>"0x00 08:方法描述符索引为#8,对应的是"()V"0x00 01:属性表数量为1(一个属性表)那么这里涉及到了属性表。什么是属性表呢?可以这么理解,它是为了描述一些专有信息的,上面的方法带有一张属性表。所有属性表的结构如下图:一个u2的属性名称索引,一个u2的属性长度加上属性长度的info。虚拟机规范预定义的属性有很多,比如Code,LineNumberTable,LocalVariableTable,SourceFile等等,这个网上可以搜索到。按照上面的表结构解析得到下面信息:

Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15

00001344   00 23 00 00 00 3B 00 01  00 01 00 00 00 09 2A B7    #   ;        *?00001360   00 01 2A B7 00 02 B1 00  00 00 02 00 24 00 00 00     *? ?    $   00001376   0E 00 03 00 00 00 12 00  04 00 13 00 08 00 14 00                   00001392   25 00 00 00 0C 00 01 00  00 00 09 00 26 00 27 00   %           & ' 00001408   00 00 02 00 28 00 22 00  01 00 23 00 00 00 63 00       ( "   #   c 00001424   03 00 01 00 00 00 20 2A  B4 00 03 9A 00 1B B2 00          *? ? ?00001440   04 12 05 B6 00 06 2A BB  00 07 59 B7 00 08 B5 00      ? *? Y? ?00001456   09 2A 04 B5 00 03 B1 00  00 00 03 00 24 00 00 00    * ? ?    $   00001472   16 00 05 00 00 00 17 00  07 00 18 00 0F 00 19 00                   00001488   1A 00 1A 00 1F 00 1C 00  25 00 00 00 0C 00 01 00           %       00001504   00 00 20 00 26 00 27 00  00 00 29 00 00 00 03 00       & '   )     00001520   01 1F 00 01 00 2A 00 2B  00 02 00 23 00 00 00 6C        * +   #   l00001536   00 02 00 02 00 00 00 28  BB 00 0A 59 B7 00 0B 4C          (? Y? L00001552   2B 12 0C B6 00 0D 2B 10  0C B8 00 0E B6 00 0F 2B   +  ? +  ? ? +00001568   12 10 B6 00 11 2A B4 00  09 2B B9 00 12 02 00 B0     ? *? +?   ?

0x0023:名称索引为#35("Code")。0x0000 003B: 属性长度为59字节。那么接下来解析一个Code属性表,按照下图解析Code Attributetypedescriptorremarku2attribute_name_indexconstant_pool中的索引,CONSTANT_Utf8_info类型。指定Attribute的名称("Code")。u4attribute_length该Attribute内容的字节长度。u2max_stack该方法操作栈的最大深度。u2max_locals该方法调用时需要分配的局部变量的最大个数,包括该方法的参数。u4code_length该方法字节码长度(以字节为单位)u1code[code_length]存放字节码数组(字节码如何解析?)。u2exception_table_length异常表的长度。exception_table_info每个表项记录一段异常处理代码信息和范围。u2start_pc记录应用该项异常处理的起始字节码。在字节码数组中的起始索引号[start_pc, end_pc)。索引号必须是opcode(一条指令的开始位置)对应的位置。u2end_pcu2handler_pc记录该项异常处理代码的开始地址。在字节码数组中的开始索引号。索引号必须是opcode对应的位置。u2catch_typeconstant_pool中的索引,CONSTANT_Class_info类型。指定该项能捕获的异常类(或其子类)。或0用于实现finally语法(即不管什么类型都会捕获。)exception_table[exception_table_length]u2attributes_countattributes包含的项目数。attribute_infoattributes[attributes_count]xxx前面6个字节(名称索引2字节+属性长度4字节)已经解析过了,所以接下来就是解析剩下的59-6=53字节即可。0x00 01: max_stack=10x00 01: max_locals=10x0000 0009: code_length=90x2A B7 00 01 2A B7 00 02 B1: 这是code代码,可以通过虚拟机字节码指令进行查找。2a=aload_0(将第一个引用变量推送到栈顶)b7=invokespecial(调用父类构造方法)00=什么都不做01=将 #1 常量池推送到栈顶,即默认"<init>":()V 构造方法2a=同上b7=同上00=什么都不做02=将#2常量池推送栈顶,即 init() 方法b1=return 从当前方法返回void整理,去除无动作指令得到下面0: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: aload_05: invokespecial #2                  // Method init:()V8: return

接下来顺着Code属性表继续解析下去:0x00 00 : exception_table_length=00x00 02 : attributes_count=2(Code属性表内部还含有2个属性表)0x00 24: 第一个属性表是"LineNumberTable"

0x00 00 00 0E : "属性长度为14″0x00 03 :line_number_table_length=3line_number_table是一个数量为line_number_table_length,类型为line_number_info的集合,line_number_info表包括了start_pc和line_number两个u2类型的数据项,前者是字节码行号,后者是Java源码行号0x00 00 : start_pc=00x00 12 : end_pc=180x00 04 : start_pc=40x00 13 : end_pc=19

0x00 25 第二个属性表是:"LocalVariableTable"

0x00 0000 0c:属性长度为120x00 01 : local_variable_table_length=1然后按照local_variable_info表结构进行解析:0x00 00 : start_pc=00x00 09:length=90x0026 : #38 name_index="this"0x0027 : #39 descriptor_index #13 ("Lcom/youge/api/ByteCodeClassKen;")0000 index=0-----------到这里第一个方法就解析完成了--------------------Method(<init>)–1个属性Code表-2个属性表(LineNumberTable ,LocalVariableTable)

3.10 Attributeattributes数组记录了和类或接口相关的所有Attribute项(和字段相关的Attribute在field_info的attributes中,和方法相关的Attribute在method_info的attrubutes中,和字节码相关的Attribute在Code Attribute的attributes中)。attributes数组中的每项都是attribute_info类型,它描述了Attribute的名称、详细信息等。该attributes数组描述了ClassFile的一些额外信息。JVM必须忽略它不能识别的Attribute,而且那些JVM不能识别的的Attribute也不能影响class文件的语义。当前定义的Attribute有:Code Attribute、Constant Value Attibute、Deprecated Attribute、Enclosing Method Attribute、Exceptions Attribute、Inner Classes Attribute、Line Number Table Attribute、Local Variable Table Attribute、Local Variable Type Table Attribute、Runtime Visible Annotations Attribute、Runtime Invisible Annotation Attribute、Runtime Visible Parameter Annotation Attribute、Runtime Invisible Parameter Annotation Attribute、Signature Attribute、Source Debug Extension Attribute、Source File Attribute、Stack Map Table Attribute、Synthetic Attribute、Annotation Default Attribute等。它们有些只存在于field_info中,有些只存在method_info中,有些只存在ClassFile中,有些只存在于Code Attribute中,还有些可以同时存在于field_info、method_info、classfile中。Attribute结构只存在与ClassFile、method_info、field_info、Code Attribute结构中。

0x0002 :同样的,表示有2个Attributes了。0x0037 : #15("SourceFile")0x0000 0002 attribute_length=20x0038 : sourcefile_index = #56("ByteCodeClassKen.java")SourceFile属性用来记录生成该Class文件的源码文件名称。

4. 直接使用 javap 反编译成可读的文本型字节码javap -verbose xxx.class

Classfile /D:/xampp/htdocs/java/mvn-local-test/target/classes/com/youge/api/ByteCodeClassKen.class  Last modified 2018-9-26; size 1801 bytes  MD5 checksum 76e207e502c3b096346480457d98cdef  Compiled from "ByteCodeClassKen.java"public class com.youge.api.ByteCodeClassKen  minor version: 0  major version: 52  flags: ACC_PUBLIC, ACC_SUPERConstant pool:    #1 = Methodref          #28.#57       // java/lang/Object."<init>":()V    #2 = Methodref          #19.#58       // com/youge/api/ByteCodeClassKen.init:()V    #3 = Fieldref           #19.#59       // com/youge/api/ByteCodeClassKen.initialed:Z    #4 = Fieldref           #60.#61       // java/lang/System.out:Ljava/io/PrintStream;    #5 = String             #62           // init...    #6 = Methodref          #63.#64       // java/io/PrintStream.println:(Ljava/lang/String;)V    #7 = Class              #65           // com/youge/service/user/UserServiceImpl    #8 = Methodref          #7.#57        // com/youge/service/user/UserServiceImpl."<init>":()V    #9 = Fieldref           #19.#66       // com/youge/api/ByteCodeClassKen.userService:Lcom/youge/service/user/UserService;   #10 = Class              #67           // com/youge/pojo/user/UserInfo   #11 = Methodref          #10.#57       // com/youge/pojo/user/UserInfo."<init>":()V   #12 = String             #68           // lilei   #13 = Methodref          #10.#69       // com/youge/pojo/user/UserInfo.setName:(Ljava/lang/String;)V   #14 = Methodref          #70.#71       // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;   #15 = Methodref          #10.#72       // com/youge/pojo/user/UserInfo.setAge:(Ljava/lang/Integer;)V   #16 = String             #73           // new road.   #17 = Methodref          #10.#74       // com/youge/pojo/user/UserInfo.setAddress:(Ljava/lang/String;)V   #18 = InterfaceMethodref #75.#76       // com/youge/service/user/UserService.addUser:(Lcom/youge/pojo/user/UserInfo;)Ljava/lang/Integer;   #19 = Class              #77           // com/youge/api/ByteCodeClassKen   #20 = Methodref          #19.#57       // com/youge/api/ByteCodeClassKen."<init>":()V   #21 = Methodref          #19.#78       // com/youge/api/ByteCodeClassKen.addUser:()Ljava/lang/Integer;   #22 = Class              #79           // java/lang/StringBuilder   #23 = Methodref          #22.#57       // java/lang/StringBuilder."<init>":()V   #24 = String             #80           // affect:   #25 = Methodref          #22.#81       // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;   #26 = Methodref          #22.#82       // java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;   #27 = Methodref          #22.#83       // java/lang/StringBuilder.toString:()Ljava/lang/String;   #28 = Class              #84           // java/lang/Object   #29 = Utf8               userService   #30 = Utf8               Lcom/youge/service/user/UserService;   #31 = Utf8               initialed   #32 = Utf8               Z   #33 = Utf8               <init>   #34 = Utf8               ()V   #35 = Utf8               Code   #36 = Utf8               LineNumberTable   #37 = Utf8               LocalVariableTable   #38 = Utf8               this   #39 = Utf8               Lcom/youge/api/ByteCodeClassKen;   #40 = Utf8               init   #41 = Utf8               StackMapTable   #42 = Utf8               addUser   #43 = Utf8               ()Ljava/lang/Integer;   #44 = Utf8               userInfo   #45 = Utf8               Lcom/youge/pojo/user/UserInfo;   #46 = Utf8               Exceptions   #47 = Class              #85           // java/lang/Exception   #48 = Utf8               main   #49 = Utf8               ([Ljava/lang/String;)V   #50 = Utf8               args   #51 = Utf8               [Ljava/lang/String;   #52 = Utf8               classKen   #53 = Utf8               affect   #54 = Utf8               Ljava/lang/Integer;   #55 = Utf8               SourceFile   #56 = Utf8               ByteCodeClassKen.java   #57 = NameAndType        #33:#34       // "<init>":()V   #58 = NameAndType        #40:#34       // init:()V   #59 = NameAndType        #31:#32       // initialed:Z   #60 = Class              #86           // java/lang/System   #61 = NameAndType        #87:#88       // out:Ljava/io/PrintStream;   #62 = Utf8               init...   #63 = Class              #89           // java/io/PrintStream   #64 = NameAndType        #90:#91       // println:(Ljava/lang/String;)V   #65 = Utf8               com/youge/service/user/UserServiceImpl   #66 = NameAndType        #29:#30       // userService:Lcom/youge/service/user/UserService;   #67 = Utf8               com/youge/pojo/user/UserInfo   #68 = Utf8               lilei   #69 = NameAndType        #92:#91       // setName:(Ljava/lang/String;)V   #70 = Class              #93           // java/lang/Integer   #71 = NameAndType        #94:#95       // valueOf:(I)Ljava/lang/Integer;   #72 = NameAndType        #96:#97       // setAge:(Ljava/lang/Integer;)V   #73 = Utf8               new road.   #74 = NameAndType        #98:#91       // setAddress:(Ljava/lang/String;)V   #75 = Class              #99           // com/youge/service/user/UserService   #76 = NameAndType        #42:#100      // addUser:(Lcom/youge/pojo/user/UserInfo;)Ljava/lang/Integer;   #77 = Utf8               com/youge/api/ByteCodeClassKen   #78 = NameAndType        #42:#43       // addUser:()Ljava/lang/Integer;   #79 = Utf8               java/lang/StringBuilder   #80 = Utf8               affect:   #81 = NameAndType        #101:#102     // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;   #82 = NameAndType        #101:#103     // append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;   #83 = NameAndType        #104:#105     // toString:()Ljava/lang/String;   #84 = Utf8               java/lang/Object   #85 = Utf8               java/lang/Exception   #86 = Utf8               java/lang/System   #87 = Utf8               out   #88 = Utf8               Ljava/io/PrintStream;   #89 = Utf8               java/io/PrintStream   #90 = Utf8               println   #91 = Utf8               (Ljava/lang/String;)V   #92 = Utf8               setName   #93 = Utf8               java/lang/Integer   #94 = Utf8               valueOf   #95 = Utf8               (I)Ljava/lang/Integer;   #96 = Utf8               setAge   #97 = Utf8               (Ljava/lang/Integer;)V   #98 = Utf8               setAddress   #99 = Utf8               com/youge/service/user/UserService  #100 = Utf8               (Lcom/youge/pojo/user/UserInfo;)Ljava/lang/Integer;  #101 = Utf8               append  #102 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;  #103 = Utf8               (Ljava/lang/Object;)Ljava/lang/StringBuilder;  #104 = Utf8               toString  #105 = Utf8               ()Ljava/lang/String;{  public com.youge.api.ByteCodeClassKen();    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: aload_0         5: invokespecial #2                  // Method init:()V         8: return      LineNumberTable:        line 18: 0        line 19: 4        line 20: 8      LocalVariableTable:        Start  Length  Slot  Name   Signature            0       9     0  this   Lcom/youge/api/ByteCodeClassKen;

public java.lang.Integer addUser() throws java.lang.Exception;    descriptor: ()Ljava/lang/Integer;    flags: ACC_PUBLIC    Code:      stack=2, locals=2, args_size=1         0: new           #10                 // class com/youge/pojo/user/UserInfo         3: dup         4: invokespecial #11                 // Method com/youge/pojo/user/UserInfo."<init>":()V         7: astore_1         8: aload_1         9: ldc           #12                 // String lilei        11: invokevirtual #13                 // Method com/youge/pojo/user/UserInfo.setName:(Ljava/lang/String;)V        14: aload_1        15: bipush        12        17: invokestatic  #14                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;        20: invokevirtual #15                 // Method com/youge/pojo/user/UserInfo.setAge:(Ljava/lang/Integer;)V        23: aload_1        24: ldc           #16                 // String new road.        26: invokevirtual #17                 // Method com/youge/pojo/user/UserInfo.setAddress:(Ljava/lang/String;)V        29: aload_0        30: getfield      #9                  // Field userService:Lcom/youge/service/user/UserService;        33: aload_1        34: invokeinterface #18,  2           // InterfaceMethod com/youge/service/user/UserService.addUser:(Lcom/youge/pojo/user/UserInfo;)Ljava/lang/Integer;        39: areturn      LineNumberTable:        line 31: 0        line 32: 8        line 33: 14        line 34: 23        line 35: 29      LocalVariableTable:        Start  Length  Slot  Name   Signature            0      40     0  this   Lcom/youge/api/ByteCodeClassKen;            8      32     1 userInfo   Lcom/youge/pojo/user/UserInfo;    Exceptions:      throws java.lang.Exception

public static void main(java.lang.String[]) throws java.lang.Exception;    descriptor: ([Ljava/lang/String;)V    flags: ACC_PUBLIC, ACC_STATIC    Code:      stack=3, locals=3, args_size=1         0: new           #19                 // class com/youge/api/ByteCodeClassKen         3: dup         4: invokespecial #20                 // Method "<init>":()V         7: astore_1         8: aload_1         9: invokevirtual #21                 // Method addUser:()Ljava/lang/Integer;        12: astore_2        13: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;        16: new           #22                 // class java/lang/StringBuilder        19: dup        20: invokespecial #23                 // Method java/lang/StringBuilder."<init>":()V        23: ldc           #24                 // String affect:        25: invokevirtual #25                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;        28: aload_2        29: invokevirtual #26                 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;        32: invokevirtual #27                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;        35: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V        38: return      LineNumberTable:        line 40: 0        line 41: 8        line 42: 13        line 43: 38      LocalVariableTable:        Start  Length  Slot  Name   Signature            0      39     0  args   [Ljava/lang/String;            8      31     1 classKen   Lcom/youge/api/ByteCodeClassKen;           13      26     2 affect   Ljava/lang/Integer;    Exceptions:      throws java.lang.Exception}SourceFile: "ByteCodeClassKen.java"

原文  http://www.cnblogs.com/yougewe/p/9710142.html
正文到此结束
Loading...