类文件由单个ClassFile结构组成
全局规范:
文件中的数据项,无论是顺序还是数量,甚至于数据存储的字节序(Byte Ordering,Class文件中字节序为Big-Endian)这样的细节,都是被严格限定的,哪个字节代表什么含义,长度是多少,先后顺序如何,都不允许改变。
ClassFile { u4 magic; //Class文件的标志 u2 minor_version; //Class的小版本号 u2 major_version; //Class的大版本号 u2 constant_pool_count; //常量池的数量 cp_info constant_pool[constant_pool_count-1]; //常量池 u2 access_flags; //Class的访问标记 u2 this_class; //当前类 u2 super_class; //父类 u2 interfaces_count; //接口 u2 interfaces[interfaces_count]; //一个类可以实现多个接口 u2 fields_count; //Class文件的字段属性 field_info fields[fields_count]; //一个类会可以有个字段 u2 methods_count; //Class文件的方法数量 method_info methods[methods_count]; //一个类可以有个多个方法 u2 attributes_count; //此类的属性表中的属性数 attribute_info attributes[attributes_count]; //属性表集合 }
u4 magic; //Class文件的标志
The magic
item supplies the magic number identifying the class
file format; it has the value 0xCAFEBABE
.
每个 Class 文件的头四个字节称为魔数(Magic Number),它的唯一作用是确定这个文件是否为一个能被虚拟机接收的 Class 文件。
程序设计者很多时候都喜欢用一些特殊的数字表示固定的文件类型或者其它特殊的含义。
u2 minor_version; //Class的小版本号 u2 major_version; //Class的大版本号
紧接着魔数的四个字节存储的是 Class 文件的版本号:第五和第六是次版本号,第七和第八是主版本号。
高版本的 Java 虚拟机可以执行低版本编译器生成的 Class 文件,但是低版本的 Java 虚拟机不能执行高版本编译器生成的 Class 文件。
u2 constant_pool_count; //常量池的数量 cp_info constant_pool[constant_pool_count-1]; //常量池
紧接着主次版本号之后的是常量池,常量池的数量是 constant pool count-1(常量池计数器是从1开始计数的,将第0项常量空出来是有特殊考虑的,索引值为0代表“不引用任何一个常量池项”)。
常量池主要存放两大常量:
字面量和符号引用。字面量比较接近于 Java 语言层面的的常量概念,如文本字符串、声明为 final 的常量值等。而符号引用则属于编译原理方面的概念。包括下面三类常量:
public class Test { private int int_num = 12; private byte byte_num = 121; private short short_num = 30; private char char_num = 'a'; private float float_num = 45.3f; //字面量 private double double_num = 39.8; //字面量 private long long_num = 2323L; //字面量 private boolean boolean_flag = true; private long long_delay_num; public void test() { final int a_test = 123; String b_test = "b_test_part"; //字面量 this.long_delay_num = 5555L; //字面量 } }
所有的常量项在常量池表都有以下结构:
cp_info { u1 tag; u1 info[]; }
以一个字节的tag开始,代表当前常量属于哪种常量类型,共有14种类型(见 Table. Constant pool tags )。
info数组的内容格式随tag不同而不同,每个tag字节后必须跟两个或多个字节,以提供有关特定常数的信息。
Table. Constant pool tags
| Constant Type | Value | 描述 | | --- | --- | --- | | CONSTANT_Class
| 7 | 类或接口的符号引用 | | CONSTANT_Fieldref
| 9 | 字段的符号引用 | | CONSTANT_Methodref
| 10 | 类中方法的符号引用 | | CONSTANT_InterfaceMethodref
| 11 | 接口中方法的符号引用 | | CONSTANT_String
| 8 | 字符串类型字面量 | | CONSTANT_Integer
| 3 | 整型字面量 | | CONSTANT_Float
| 4 | 浮点型字面量 | | CONSTANT_Long
| 5 | 长整型字面量 | | CONSTANT_Double
| 6 | 双精度浮点型字面量 | | CONSTANT_NameAndType
| 12 | 字段或方法的符号引用 | | CONSTANT_Utf8
| 1 | UTF-8编码的字符串 | | CONSTANT_MethodHandle
| 15 | 方法句柄 | | CONSTANT_MethodType
| 16 | 方法类型 | | CONSTANT_InvokeDynamic
| 18 | 动态方法调用点 |
CONSTANT_Class_info { u1 tag; u2 name_index; }
name index: 指向CONSTANT Utf8_info常量项的合法索引值,表示一个二进制类或接口名( Binary Class and Interface Names )。
For example, the normal binary name of class _ Thread
is java.lang.Thread
. In the internal form used in descriptors in the class
file format, a reference to the name of class Thread
is implemented using a CONSTANT_Utf8_info
structure representing the string java/lang/Thread
._
For example, the class name representing the two-dimensional array type _ int[][]
is [[I
, while the class name representing the type Thread[]
is [Ljava/lang/Thread;
._ _An array type descriptor is valid only if it represents 255 or fewer dimensions.
CONSTANT_Fieldref_info { u1 tag; u2 class_index; u2 name_and_type_index; } CONSTANT_Methodref_info { u1 tag; u2 class_index; u2 name_and_type_index; } CONSTANT_InterfaceMethodref_info { u1 tag; u2 class_index; u2 name_and_type_index; }
The value of the class_index
item must be a valid index into the constant_pool
table. The constant_pool
entry at that index must be a CONSTANT_Class_info
structure ( §4.4.1 ) representing a class or interface type that has the field or method as a member.
class_index
item of a CONSTANT_Methodref_info
structure must be a class type, not an interface type. class_index
item of a CONSTANT_InterfaceMethodref_info
structure must be an interface type. class_index
item of a CONSTANT_Fieldref_info
structure may be either a class type or an interface type. The value of the name_and_type_index
item must be a valid index into the constant_pool
table. The constant_pool
entry at that index must be a CONSTANT_NameAndType_info
structure ( §4.4.6 ). This constant_pool
entry indicates the name and descriptor of the field or method.
In a CONSTANT_Fieldref_info
, the indicated descriptor must be a field descriptor ( §4.3.2 ). Otherwise, the indicated descriptor must be a method descriptor ( §4.3.3 ).
If the name of the method of a CONSTANT_Methodref_info
structure begins with a ' <
' (' /u003c
'), then the name must be the special name <init>
, representing an instance initialization method ( §2.9 ). The return type of such a method must be void
.
CONSTANT_String_info { u1 tag; u2 string_index; }
string index: 指向CONSTANT Utf8_info常量项的合法索引值,表示一个字符串字面量。
The value of the string_index
item must be a valid index into the constant_pool
table. The constant_pool
entry at that index must be a CONSTANT_Utf8_info
structure ( §4.4.7 ) representing the sequence of Unicode code points to which the String
object is to be initialized.
CONSTANT_Integer_info { u1 tag; u4 bytes; } CONSTANT_Float_info { u1 tag; u4 bytes; }
bytes: 按照高位在前存储的int值/float值
CONSTANT_Long_info { u1 tag; u4 high_bytes; u4 low_bytes; } CONSTANT_Double_info { u1 tag; u4 high_bytes; u4 low_bytes; }
high bytes low bytes: 按照高位在前存储的long值/double值
CONSTANT_NameAndType_info { u1 tag; u2 name_index; u2 descriptor_index; }
info常量项的合法索引值,表示该字段或方法名称。
descriptor
index: 指向CONSTANT Utf8 info常量项的合法索引值,表示该字段或方法描述符。CONSTANT_Utf8_info { u1 tag; u2 length; u1 bytes[length]; }
UTF-8编码的字符串长度和字节数组
CONSTANT_MethodHandle_info { u1 tag; u1 reference_kind; u2 reference_index; }
The value of the reference_kind
item must be in the range 1 to 9. The value denotes the kind of this method handle, which characterizes its bytecode behavior ( §5.4.3.5 ).
The value of the reference_index
item must be a valid index into the constant_pool
table. The constant_pool
entry at that index must be as follows:
reference_kind
item is 1 ( REF_getField
), 2 ( REF_getStatic
), 3 ( REF_putField
), or 4 ( REF_putStatic
), then the constant_pool
entry at that index must be a CONSTANT_Fieldref_info
( §4.4.2 ) structure representing a field for which a method handle is to be created. reference_kind
item is 5 ( REF_invokeVirtual
) or 8 ( REF_newInvokeSpecial
), then the constant_pool
entry at that index must be a CONSTANT_Methodref_info
structure ( §4.4.2 ) representing a class's method or constructor ( §2.9 ) for which a method handle is to be created. reference_kind
item is 6 ( REF_invokeStatic
) or 7 ( REF_invokeSpecial
), then if the class
file version number is less than 52.0, the constant_pool
entry at that index must be a CONSTANT_Methodref_info
structure representing a class's method for which a method handle is to be created; if the class
file version number is 52.0 or above, the constant_pool
entry at that index must be either a CONSTANT_Methodref_info
structure or a CONSTANT_InterfaceMethodref_info
structure ( §4.4.2 ) representing a class's or interface's method for which a method handle is to be created. reference_kind
item is 9 ( REF_invokeInterface
), then the constant_pool
entry at that index must be a CONSTANT_InterfaceMethodref_info
structure representing an interface's method for which a method handle is to be created. If the value of the reference_kind
item is 5 ( REF_invokeVirtual
), 6 ( REF_invokeStatic
), 7 ( REF_invokeSpecial
), or 9 ( REF_invokeInterface
), the name of the method represented by a CONSTANT_Methodref_info
structure or a CONSTANT_InterfaceMethodref_info
structure must not be <init>
or <clinit>
.
If the value is 8 ( REF_newInvokeSpecial
), the name of the method represented by a CONSTANT_Methodref_info
structure must be <init>
.
CONSTANT_MethodType_info { u1 tag; u2 descriptor_index; }
descriptor index: 指向CONSTANT Utf8_info常量项的合法索引值,表示方法的描述符
CONSTANT_InvokeDynamic_info { u1 tag; u2 bootstrap_method_attr_index; u2 name_and_type_index; }
*bootstrap_method_attr_index: *
The value of the bootstrap_method_attr_index
item must be a valid index into the bootstrap_methods
array of the bootstrap method table ( §4.7.23 ) of this class
file.
name and type index:
指向CONSTANTNameAndType_info常量项的有效索引,表示方法名和方法描述符。
在常量池结束之后,紧接着的2个字节代表访问标志(access_flag),这个标志用于识别一些类或接口层次的访问信息,包括:这个Class是类还是接口,是否定义为public类型,abstract类型,如果是类的话,是否声明为final,等等。每种访问信息都由一个十六进制的标志值表示,如果同时具有多种访问信息,则得到的标志值为这几种访问信息的标志值的逻辑或。
类访问和属性修饰符:
| Flag Name | Value | Interpretation | | --- | --- | --- | | ACC_PUBLIC
| 0x0001 | Declared public
; may be accessed from outside its package. | | ACC_FINAL
| 0x0010 | Declared final
; no subclasses allowed. | | ACC_SUPER
| 0x0020 | Treat superclass methods specially when invoked by the invokespecial instruction. | | ACC_INTERFACE
| 0x0200 | Is an interface, not a class. | | ACC_ABSTRACT
| 0x0400 | Declared abstract
; must not be instantiated. | | ACC_SYNTHETIC
| 0x1000 | Declared synthetic; not present in the source code. | | ACC_ANNOTATION
| 0x2000 | Declared as an annotation type. | | ACC_ENUM
| 0x4000 | Declared as an enum
type. |
u2 this_class;//当前类 u2 super_class;//父类 u2 interfaces_count;//接口 u2 interfaces[interfaces_count];//一个雷可以实现多个接口
类索引(this class)和父类索引(super class)都是一个u2类型的数据,而接口索引集合(interfaces)则是一组u2类型的数据集合,Class文件中由这三项数据来确定这个类的继承关系。
类索引、父类索引和接口索引集合都按照顺序排列在访问标志之后,类索引和父类索引两个u2类型的索引值表示,它们各自指向一个类型为COMNSTANT Class info的类描述符常量,通过该常量中的索引值找到定义在COMNSTANT Utf8 info类型的常量中的全限定名字符串。
而接口索引集合就用来描述这个类实现了哪些接口,这些被实现的接口将按implements语句(如果这个类本身是个接口,则应当是extend语句)后的接口顺序从左到右排列在接口的索引集合中。
u2 fields_count;//Class 文件的字段的个数 field_info fields[fields_count];//一个类会可以有个字段
字段结构(field_info)用于描述接口或类中声明的变量。字段包括了类级变量或实例级变量,但不包括在方法内声明的变量。字段的名字、数据类型、修饰符等都是无法固定的,只能引用常量池中的常量来描述。下面是字段结构的格式
field_info { u2 access_flags; u2 name_index; u2 descriptor_index; u2 attributes_count; attribute_info attributes[attributes_count]; }
字段的作用域( public
, private
, protected
修饰符),是实例变量还是类变量( static
修饰符),可否被序列化(transient 修饰符),可变性(final),可见性(volatile 修饰符,是否强制从主内存读写)。
| Flag Name | Value | Interpretation | | --- | --- | --- | | ACC_PUBLIC
| 0x0001 | Declared public
; may be accessed from outside its package. | | ACC_PRIVATE
| 0x0002 | Declared private
; usable only within the defining class. | | ACC_PROTECTED
| 0x0004 | Declared protected
; may be accessed within subclasses. | | ACC_STATIC
| 0x0008 | Declared static
. | | ACC_FINAL
| 0x0010 | Declared final
; never directly assigned to after object construction (JLS §17.5). | | ACC_VOLATILE
| 0x0040 | Declared volatile
; cannot be cached. | | ACC_TRANSIENT
| 0x0080 | Declared transient
; not written or read by a persistent object manager. | | ACC_SYNTHETIC
| 0x1000 | Declared synthetic; not present in the source code. | | ACC_ENUM
| 0x4000 | Declared as an element of an enum
. |
对CONSTANT Utf8 info常量项的引用,表示字段的名称;
这里对应的是简单名称:
简单名称是指没有类型或参数修饰的方法或字段名称,如果一个类中有这样一个方法boolean get(int name)和一个变量private final static int m,则他们的简单名称则分别为get() 和 m。
对CONSTANT Utf8 info常量项的引用,表示字段描述符;
而描述符的作用则是用来描述字段的数据类型、方法的参数列表(包括数量、类型以及顺序等)和返回值的。根据描述符规则,详细的描述符标示字的含义如下表所示
| FieldType term | Type | Interpretation | | --- | --- | --- | | B
| byte
| signed byte | | C
| char
| Unicode character code point in the Basic Multilingual Plane, encoded with UTF-16 | | D
| double
| double-precision floating-point value | | F
| float
| single-precision floating-point value | | I
| int
| integer | | J
| long
| long integer | | L
ClassName ;
| reference
| an instance of class ClassName | | S
| short
| signed short | | Z
| boolean
| true
or false
| | [
| reference
| one array dimension |
The field descriptor of an instance variable of type int
is simply I
. The field descriptor of an instance variable of type Object
is Ljava/lang/Object;
. Note that the internal form of the binary name for class Object
is used. The field descriptor of an instance variable of the multidimensional array type double[][][]
is [[[D
.
对于方法描述符:
用方法描述符描述方法时,按照先参数后返回值的顺序描述,参数要按照严格的顺序放在一组小括号内,如方法Object m(int i, double d, Thread t) {...}的描述符为(IDLjava/lang/Thread;)Ljava/lang/Object。
一个字段还会拥有一些额外的属性,attributes_count 存放属性的个数;
存放具体属性具体内容。
比如,如果在类中有如下字段的声明: final int i = 123;那就会存在一项名为ConstantValue的属性,它指向常量123 。关于attribute_info的详细内容,在后面关于属性集合中会有详细介绍。
最后需要注意一点:字段集合中不会列出从父类或接口中继承而来的字段,但有可能列出原本Java代码中不存在的字段。比如在内部类中为了保持对外部类的访问性,会自动添加指向外部类实例的字段。
u2 methods_count;//Class 文件的方法的数量 method_info methods[methods_count];//一个类可以有个多个方法
method_info结构:
method_info { u2 access_flags; u2 name_index; u2 descriptor_index; u2 attributes_count; attribute_info attributes[attributes_count]; }
table. ** access flags**_
| Flag Name | Value | Interpretation | | --- | --- | --- | | ACC_PUBLIC
| 0x0001 | Declared public
; may be accessed from outside its package. | | ACC_PRIVATE
| 0x0002 | Declared private
; accessible only within the defining class. | | ACC_PROTECTED
| 0x0004 | Declared protected
; may be accessed within subclasses. | | ACC_STATIC
| 0x0008 | Declared static
. | | ACC_FINAL
| 0x0010 | Declared final
; must not be overridden ( §5.4.5 ). | | ACC_SYNCHRONIZED
| 0x0020 | Declared synchronized
; invocation is wrapped by a monitor use. | | ACC_BRIDGE
| 0x0040 | A bridge method, generated by the compiler. | | ACC_VARARGS
| 0x0080 | Declared with variable number of arguments. | | ACC_NATIVE
| 0x0100 | Declared native
; implemented in a language other than Java. | | ACC_ABSTRACT
| 0x0400 | Declared abstract
; no implementation is provided. | | ACC_STRICT
| 0x0800 | Declared strictfp
; floating-point mode is FP-strict. | | ACC_SYNTHETIC
| 0x1000 | Declared synthetic; not present in the source code. |
注意:因为 volatile
修饰符和 transient
修饰符不可以修饰方法,所以方法表的访问标志中没有这两个对应的标志,但是增加了 synchronized
、 native
、 abstract
等关键字修饰方法,所以也就多了这些关键字对应的标志。
方法里的Java代码,经过编译器编译成字节码指令后,存放在方法属性集合中一个名为Code的属性里。
与字段集合对应,如果父类方法在子类中没有被覆写,方法集合中就不会出现来自父类的方法信息。但同样,有可能会出现由编译器自动添加的方法,最典型的便是类构造器“
在Java语言中,要重载一个方法,除了要与原方法具有相同的简单名称外,还要求必须拥有一个与原方法不同的特征签名,特征签名就是一个方法中各个参数在常量池中的字段符号引用的集合,也就是因为返回值不会包含在特征签名之中,因此Java语言里无法仅仅依靠返回值的不同来对一个已有方法进行重载。
u2 attributes_count;//此类的属性表中的属性数 attribute_info attributes[attributes_count];//属性表集合
attribute_info结构:
attribute_info { u2 attribute_name_index; u4 attribute_length; u1 info[attribute_length]; }
attribute name index: 指向CONSTANT Utf8 info的索引值,表示属性名称。
attribute_length: 每个属性值的结构是完全可以自定义的,只需说明属性值所占用的位数长度即可。
在 Class 文件,字段集合,方法集合中都可以携带自己的属性集合,以用于描述某些场景专有的信息。与 Class 文件中其它的数据项目要求的顺序、长度和内容不同,属性集合的限制稍微宽松一些,不再要求各个属性具有严格的顺序,并且只要不与已有的属性名重复,任何人实现的编译器都可以向属性中写入自己定义的属性信息,Java虚拟机运行时会忽略掉它不认识的属性。
JVM规范中预定义了多项JVM应能识别的属性( 官方说明 )。
Java程序方法体中的代码讲过Javac编译后,生成的字节码指令便会存储在Code属性中,但并非所有的方法表都必须存在这个属性,比如接口或抽象类中的方法就不存在Code属性。
结构如下:
Code_attribute { u2 attribute_name_index; u4 attribute_length; u2 max_stack; u2 max_locals; u4 code_length; u1 code[code_length]; u2 exception_table_length; { 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]; }
attribute name index是一项指向CONSTANT Utf8 info型常量的索引,常量值固定为“Code”,它代表了该属性的名称。attribute_length指示了属性值的长度,由于属性名称索引与属性长度一共是6个字节,所以属性值的长度固定为整个属性表的长度减去6个字节。
max stack代表了操作数栈深度的最大值,max locals代表了局部变量表所需的存储空间,它的单位是Slot,并不是在方法中用到了多少个局部变量,就把这些局部变量所占Slot之和作为max_locals的值,原因是局部变量表中的Slot可以重用。
code length和code用来存储Java源程序编译后生成的字节码指令。code用于存储字节码指令的一系列字节流,它是u1类型的单字节,因此取值范围为0x00到0xFF,那么一共可以表达256条指令,目前,Java虚拟机规范已经定义了其中200条编码值对应的指令含义。code length虽然是一个u4类型的长度值,理论上可以达到2^32-1,但是虚拟机规范中限制了一个方法不允许超过 65535条字节码指令 ,如果超过了这个限制,Javac编译器将会拒绝编译。
table),它对于Code属性来说并不是必须存在的。
它包含四个字段,这些字段的含义为:如果字节码从第start
pc行到第end pc行之间(不含end pc行)出现了类型为catch type或其子类的异常(catch type为指向一个CONSTANT Class info型常量的索引),则转到第handler pc行继续处理,当catch type的值为0时,代表人和的异常情况都要转到handler_pc处进行处理。异常表实际上是Java代码的一部分,编译器使用异常表而不是简单的跳转命令来实现Java异常即finally处理机制,也因此,finally中的内容会在try或catch中的return语句之前执行,并且在try或catch跳转到finally之前,会将其内部需要返回的变量的值复制一份副本到最后一个本地变量表(LocalVariableTable)的Slot中,也因此便有了如下的情况try语句在返回前,将其他所有的操作执行完,保留好要返回的值,而后转入执行finally中的语句,而后分为以下三种情况: 情况一:如果finally中有return语句,则会将try中的return语句”覆盖“掉,直接执行finally中的return语句,得到返回值,这样便无法得到try之前保留好的返回值。 情况二:如果finally中没有return语句,也没有改变要返回值,则执行完finally中的语句后,会接着执行try中的return语句,返回之前保留的值。 情况三:如果finally中没有return语句,但是改变了要返回的值,这里有点类似与引用传递和值传递的区别,分以下两种情况: 1)如果return的数据是基本数据类型或文本字符串,则在finally中对该基本数据的改变不起作用,try中的return语句依然会返回进入finally块之前保留的值。 2)如果return的数据是引用数据类型,而在finally中对该引用数据类型的属性值的改变起作用,try中的return语句返回的就是在finally中改变后的该属性的值。
Code属性是Class文件中最重要的一个属性,如果把一个Java程序中的信息分为代码和元数据两部分,那么在整个Class文件里,Code属性用于描述代码,所有的其他数据项目都用于描述元数据。
Exceptions_attribute { u2 attribute_name_index; u4 attribute_length; u2 number_of_exceptions; u2 exception_index_table[number_of_exceptions]; }
这里的Exception属性的作用是列举出方法中可能抛出的受查异常,也就是方法描述时在throws关键字后面列举的异常。它的结构很简单,只有attribute name index、attribute length、number of exceptions、exception index_table四项,从字面上便很容易理解。
LineNumberTable属性 *_ (使用位置:Code)*_
它用于描述Java源码行号与字节码行号之间的对应关系。
LocalVariableTable属性 *_ (使用位置:Code)*_
它用于描述栈帧中局部变量表中的变量与Java源码中定义的变量之间的对应关系。
它用于记录生成这个Class文件的源码文件名称。
只有被final修饰的成员变量才有ConstantValue属性
该属性用于记录内部类与宿主类之间的关联。如果一个类中定义了内部类,那么编译器将会为它及它所包含的内部类生成InnerClasses属性。
该属性用于表示某个类、字段和方法,已经被程序作者定为不再推荐使用,它可以通过在代码中使用@Deprecated注释进行设置。
该属性代表此字段或方法并不是Java源代码直接生成的,而是由编译器自行添加的,如this字段和实例构造器、类构造器等。
在Idea中安装jclasslib Bytecode viewer插件
在上文中介绍字面量时使用了Test类 可以看到这样的结构
javap分析class文件用法:javap -v class文件名
在上文中介绍字面量时使用了Test类 执行:
javap -v Test.class
可以具体的看到常量池的信息
Classfile /Users/yulian/soho/projects/road-java/road-java-pure/target/classes/com/pioneerzcy/pure/literal/Test.class Last modified 2019-10-25; size 877 bytes MD5 checksum b221862f6c7fe428efef23582a5da234 Compiled from "Test.java" public class com.pioneerzcy.pure.literal.Test minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #20.#51 // java/lang/Object."<init>":()V #2 = Fieldref #19.#52 // com/pioneerzcy/pure/literal/Test.int_num:I #3 = Fieldref #19.#53 // com/pioneerzcy/pure/literal/Test.byte_num:B #4 = Fieldref #19.#54 // com/pioneerzcy/pure/literal/Test.short_num:S #5 = Fieldref #19.#55 // com/pioneerzcy/pure/literal/Test.char_num:C #6 = Float 45.3f #7 = Fieldref #19.#56 // com/pioneerzcy/pure/literal/Test.float_num:F #8 = Double 39.8d #10 = Fieldref #19.#57 // com/pioneerzcy/pure/literal/Test.double_num:D #11 = Long 2323l #13 = Fieldref #19.#58 // com/pioneerzcy/pure/literal/Test.long_num:J #14 = Fieldref #19.#59 // com/pioneerzcy/pure/literal/Test.boolean_flag:Z #15 = String #60 // b_test_part #16 = Long 5555l #18 = Fieldref #19.#61 // com/pioneerzcy/pure/literal/Test.long_delay_num:J #19 = Class #62 // com/pioneerzcy/pure/literal/Test #20 = Class #63 // java/lang/Object #21 = Utf8 int_num #22 = Utf8 I #23 = Utf8 byte_num #24 = Utf8 B #25 = Utf8 short_num #26 = Utf8 S #27 = Utf8 char_num #28 = Utf8 C #29 = Utf8 float_num #30 = Utf8 F #31 = Utf8 double_num #32 = Utf8 D #33 = Utf8 long_num #34 = Utf8 J #35 = Utf8 boolean_flag #36 = Utf8 Z #37 = Utf8 long_delay_num #38 = Utf8 <init> #39 = Utf8 ()V #40 = Utf8 Code #41 = Utf8 LineNumberTable #42 = Utf8 LocalVariableTable #43 = Utf8 this #44 = Utf8 Lcom/pioneerzcy/pure/literal/Test; #45 = Utf8 test #46 = Utf8 a_test #47 = Utf8 b_test #48 = Utf8 Ljava/lang/String; #49 = Utf8 SourceFile #50 = Utf8 Test.java #51 = NameAndType #38:#39 // "<init>":()V #52 = NameAndType #21:#22 // int_num:I #53 = NameAndType #23:#24 // byte_num:B #54 = NameAndType #25:#26 // short_num:S #55 = NameAndType #27:#28 // char_num:C #56 = NameAndType #29:#30 // float_num:F #57 = NameAndType #31:#32 // double_num:D #58 = NameAndType #33:#34 // long_num:J #59 = NameAndType #35:#36 // boolean_flag:Z #60 = Utf8 b_test_part #61 = NameAndType #37:#34 // long_delay_num:J #62 = Utf8 com/pioneerzcy/pure/literal/Test #63 = Utf8 java/lang/Object { public com.pioneerzcy.pure.literal.Test(); descriptor: ()V flags: ACC_PUBLIC Code: stack=3, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: aload_0 5: bipush 12 7: putfield #2 // Field int_num:I 10: aload_0 11: bipush 121 13: putfield #3 // Field byte_num:B 16: aload_0 17: bipush 30 19: putfield #4 // Field short_num:S 22: aload_0 23: bipush 97 25: putfield #5 // Field char_num:C 28: aload_0 29: ldc #6 // float 45.3f 31: putfield #7 // Field float_num:F 34: aload_0 35: ldc2_w #8 // double 39.8d 38: putfield #10 // Field double_num:D 41: aload_0 42: ldc2_w #11 // long 2323l 45: putfield #13 // Field long_num:J 48: aload_0 49: iconst_1 50: putfield #14 // Field boolean_flag:Z 53: return LineNumberTable: line 8: 0 line 10: 4 line 11: 10 line 12: 16 line 13: 22 line 14: 28 line 15: 34 line 16: 41 line 17: 48 LocalVariableTable: Start Length Slot Name Signature 0 54 0 this Lcom/pioneerzcy/pure/literal/Test; public void test(); descriptor: ()V flags: ACC_PUBLIC Code: stack=3, locals=3, args_size=1 0: bipush 123 2: istore_1 3: ldc #15 // String b_test_part 5: astore_2 6: aload_0 7: ldc2_w #16 // long 5555l 10: putfield #18 // Field long_delay_num:J 13: return LineNumberTable: line 21: 0 line 22: 3 line 23: 6 line 24: 13 LocalVariableTable: Start Length Slot Name Signature 0 14 0 this Lcom/pioneerzcy/pure/literal/Test; 3 11 1 a_test I 6 8 2 b_test Ljava/lang/String; } SourceFile: "Test.java"