手工解读 Java 的 Class 文件(JDK8)

通过手工解析一个简单的 Java 程序所编译的 Class 文件,来了解,学习 Class 文件结构。

一、工具准备

介绍编译环境和工具。

二、开始解读

2.1、代码

2.1.1、Java 源码

package com.hyl.learnerJVM.classtest;

/**
 * class测试类
 *
 * @author hyl
 * @version v1.0: ClassTest.java, v 0.1 2020/8/7 8:03 $
 */
public class ClassTest {

    private long n;

    public long inLong() {
        return n + 1;
    }
}

2.1.2、class 文件源码

在这里插入图片描述

2.2、开始解读

首先需要了解 class 文件的整体结构。

根据《Java 虚拟机规范》结构如下

ClassFile {
    u4             magic;
    u2             minor_version;
    u2             major_version;
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    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];
}

来自 https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.1

接下来按照这个结构顺序解读。

2.2.1 magic

u4:4 个字节

Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000000   CA FE BA BE

魔数(Magic Number),唯一作用是确定这个文件是否为一个能被虚拟机接受的 Class 文件。(“cafe babe” 和 “Java” 也算是个彩蛋)

官方说明:

The magic item supplies the magic number identifying the class file format; it has the value 0xCAFEBABE.

2.2.2 minor_version

u2:2 个字节

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

次版本号,曾经在 Java 2 中出现过,以后,就再也没有被使用过了,基本上固定为零了。

2.2.3 major_version

u2:2 个字节

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

主版本号,Java 版本从 45 开始,JDK 1.1 以后每个大版本加 1 ,这里 52(0x34)就是 JDK1.8 的意思。

官方说明:

The values of the minor_version and major_version items are the minor and major version numbers of this class file. Together, a major and a minor version number determine the version of the class file format. If a class file has major version number M and minor version number m, we denote the version of its class file format as M.m. Thus, class file format versions may be ordered lexicographically, for example, 1.5 < 2.0 < 2.1.
A Java Virtual Machine implementation can support a class file format of version v if and only if v lies in some contiguous range Mi.0 ≤ v ≤ Mj.m. The release level of the Java SE platform to which a Java Virtual Machine implementation conforms is responsible for determining the range.
Oracle’s Java Virtual Machine implementation in JDK release 1.0.2 supports class file format versions 45.0 through 45.3 inclusive. JDK releases 1.1. support class file format versions in the range 45.0 through 45.65535 inclusive. For k ≥ 2, JDK release 1.k supports class file format versions in the range 45.0 through 44+k.0 inclusive.*

2.2.4 constant_pool_count

u2:2 个字节

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

常量池容量计数值,就是接下来有几个常量。这里是显示有 22(0x16)个,但是实际上只有 21 个,因为 第 0 个预留了,用于 “ 不引用任何一个常量池项目 ”,所以常量池的引用是从 1 开始。对于其他集合类型,一般都是从 0 下标开始的。

官方说明:

The value of the constant_pool_count item is equal to the number of entries in the constant_pool table plus one. A constant_pool index is considered valid if it is greater than zero and less than constant_pool_count, with the exception for constants of type long and double noted in §4.4.5.

2.2.5 constant_pool[constant_pool_count-1]

cp_info:常量表结构,长度是 constant_pool_count-1。(从上文可知是 21 个)

结构如下:

cp_info {
    u1 tag;
    u1 info[];
}

tag 的类型如下:

类型 Constant Type标志 Value描述
CONSTANT_Class7类和接口的符号引用
CONSTANT_Fieldref9字段的符号引用
CONSTANT_Methodref10类中方法的符号引用
CONSTANT_InterfaceMethodref11接口中方法的符号引用
CONSTANT_String8字符串类型字面量
CONSTANT_Integer3整型字面量
CONSTANT_Float4浮点型字面量
CONSTANT_Long5长整型字面量
CONSTANT_Double6双精度浮点型字面量
CONSTANT_NameAndType12字段或方法的部分符号引用
CONSTANT_Utf81UTF-8 编码的字符串
CONSTANT_MethodHandle15表示方法句柄
CONSTANT_MethodType16表示方法类型
CONSTANT_InvokeDynamic18表示一个动态方法调用

接下逐个常量做解读

2.2.5.1 #1
Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000000                                  0A 00 04 00 12

CONSTANT_Methodref 结构:

CONSTANT_Methodref_info {
    u1 tag;
    u2 class_index;
    u2 name_and_type_index;
}

解读:

#1 = Methodref          #4.#18
2.2.5.2 #2
Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000000                                                 09
00000016   00 03 00 13 

CONSTANT_Fieldref 结构:

CONSTANT_Fieldref_info {
    u1 tag;
    u2 class_index;
    u2 name_and_type_index;
}

解读:

#2 = Fieldref           #3.#19
2.2.5.3 #3
Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000016               07 00 14 

CONSTANT_Class 结构:

CONSTANT_Class_info {
    u1 tag;
    u2 name_index;
}

解读:

#3 = Class              #20
2.2.5.4 #4
Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000016                        07  00 15

CONSTANT_Class 结构:

CONSTANT_Class_info {
    u1 tag;
    u2 name_index;
}

解读:

#4 = Class              #21
2.2.5.5 #5
Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000016                                  01 00 01 6E

CONSTANT_Utf8 结构:

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}

解读:

#5 = Utf8               n

这里 utf-8 使用的是缩写编码。从 \u0001\u007f 之间的字符,使用一个字节(相当于1~127的ASCII码)。从\u0080\u07ff 之间采用两个字节。从 \u0800\uffff 按照普通的 UTF-8 使用三个字节。

2.2.5.6 #6
Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000016                                              01 00
00000032   01 4A 

CONSTANT_Utf8 结构:

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}

解读:

#6 = Utf8               J
2.2.5.7 #7
Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000032         01 00 06 3C 69 6E  69 74 3E 

CONSTANT_Utf8 结构:

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}

解读:

#7 = Utf8               <init>
2.2.5.8 #8
Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000032                                     01 00 03 28 29
00000048   56

CONSTANT_Utf8 结构:

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}

解读:

#8 = Utf8               ()V
2.2.5.9 #9
Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000048      01 00 04 43 6F 64 65

CONSTANT_Utf8 结构:

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}

解读:

#9 = Utf8               Code
2.2.5.10 #10
Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000048                            01 00 0F 4C 69 6E 65 4E
00000064   75 6D 62 65 72 54 61 62  6C 65

CONSTANT_Utf8 结构:

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}

解读:

#10 = Utf8               LineNumberTable
2.2.5.11 #11
Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000064                                  01 00 12 4C 6F 63
00000080   61 6C 56 61 72 69 61 62  6C 65 54 61 62 6C 65

CONSTANT_Utf8 结构:

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}

解读:

#11 = Utf8               LocalVariableTable
2.2.5.12 #12
Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000080                                                 01
00000096   00 04 74 68 69 73

CONSTANT_Utf8 结构:

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}

解读:

#12 = Utf8               this
2.2.5.13 #13
Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000096                     01 00  28 4C 63 6F 6D 2F 68 79
00000112   6C 2F 6C 65 61 72 6E 65  72 4A 56 4D 2F 63 6C 61
00000128   73 73 74 65 73 74 2F 43  6C 61 73 73 54 65 73 74
00000144   3B

CONSTANT_Utf8 结构:

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}

解读:

#13 = Utf8               Lcom/hyl/learnerJVM/classtest/ClassTest;
2.2.5.14 #14
Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000144      01 00 06 69 6E 4C 6F  6E 67

CONSTANT_Utf8 结构:

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}

解读:

#14 = Utf8               inLong
2.2.5.15 #15
Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000144                                  01 00 03 28 29 4A

CONSTANT_Utf8 结构:

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}

解读:

#15 = Utf8               ()J
2.2.5.16 #16
Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000160   01 00 0A 53 6F 75 72 63  65 46 69 6C 65

CONSTANT_Utf8 结构:

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}

解读:

#16 = Utf8               SourceFile
2.2.5.17 #17
Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000160                                           01 00 0E
00000176   43 6C 61 73 73 54 65 73  74 2E 6A 61 76 61

CONSTANT_Utf8 结构:

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}

解读:

#17 = Utf8               ClassTest.java
2.2.5.18 #18
Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000176                                              0C 00
00000192   07 00 08

CONSTANT_NameAndType 结构:

CONSTANT_NameAndType_info {
    u1 tag;
    u2 name_index;
    u2 descriptor_index;
}

解读:

#18 = NameAndType        #7:#8
2.2.5.19 #19
Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000192            0C 00 05 00 06

CONSTANT_NameAndType 结构:

CONSTANT_NameAndType_info {
    u1 tag;
    u2 name_index;
    u2 descriptor_index;
}

解读:

#19 = NameAndType        #5:#6
2.2.5.20 #20
Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000192                            01 00 26 63 6F 6D 2F 68
00000208   79 6C 2F 6C 65 61 72 6E  65 72 4A 56 4D 2F 63 6C
00000224   61 73 73 74 65 73 74 2F  43 6C 61 73 73 54 65 73
00000240   74

CONSTANT_Utf8 结构:

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}

解读:

#20 = Utf8               com/hyl/learnerJVM/classtest/ClassTest
2.2.5.21 #21
Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000240      01 00 10 6A 61 76 61  2F 6C 61 6E 67 2F 4F 62
00000256   6A 65 63 74

CONSTANT_Utf8 结构:

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}

解读:

#21 = Utf8               java/lang/Object

2.2.6 access_flags

u2:两个字节

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

访问标志,识别一些类或接口的访问信息,包括,是类还是接口;是否是 public ;是否是 abstract 类型;是否声明 final ;等等。

访问标识如下:

Flag NameValue含义Interpretation
ACC_PUBLIC0x0001是否为public 类型Declared public; may be accessed from outside its package.
ACC_FINAL0x0010是否被声明 final,只有类可设置Declared final; no subclasses allowed.
ACC_SUPER0x0020是否允许使用invokespecial 字节码指令的新语义Treat superclass methods specially when invoked by the invokespecial instruction.
ACC_INTERFACE0x0200标识这是个接口Is an interface, not a class.
ACC_ABSTRACT0x0400是否为 abstract 类型Declared abstract; must not be instantiated.
ACC_SYNTHETIC0x1000标识这个类并非由用户代码产生的Declared synthetic; not present in the source code.
ACC_ANNOTATION0x2000标识这是个注解Declared as an annotation type.
ACC_ENUM0x4000标识这是个枚举Declared as an enum type.

原文 https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.1-200-E.1

解读:

access_flags 的值为:0x0001 | 0x0020 = 0x0021

flags: ACC_PUBLIC, ACC_SUPER

2.2.7 this_class

u2:两个字节

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

类索引,确定这个类的全限名。指向一个 class 类型的常量。

官方说明:

The value of the this_class 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 the class or interface defined by this class file.

解读:

#3  = Class              #20            // com/hyl/learnerJVM/classtest/ClassTest

2.2.8 super_class

u2:两个字节

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

父类索引,确定这个父类的全限名。指向一个 class 类型常量。

官方说明:

For a class, the value of the super_class item either must be zero or must be a valid index into the constant_pool table. If the value of the super_class item is nonzero, the constant_pool entry at that index must be a CONSTANT_Class_info structure representing the direct superclass of the class defined by this class file. Neither the direct superclass nor any of its superclasses may have the ACC_FINAL flag set in the access_flags item of its ClassFile structure.
If the value of the super_class item is zero, then this class file must represent the class Object, the only class or interface without a direct superclass.
For an interface, the value of the super_class item must always be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Class_info structure representing the class Object.

解读:

#4 = Class              #21            // java/lang/Object

2.2.9 interfaces_count

u2:两个字节

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

接口计数器,表示接口索引表的容量。

官方说明:

The value of the interfaces_count item gives the number of direct superinterfaces of this class or interface type.

解读:

这里接口数量为零,所以接下来的接口索引表不存在了。

2.2.10 interfaces[interfaces_count]

u2:两个字节一组。

因为没有接口,所以这里在 class 文件中不存在。

接口索引表,包含实现的接口。

官方说明:

Each value in the interfaces array must be a valid index into the constant_pool table. The constant_pool entry at each value of interfaces[i], where 0 ≤ i < interfaces_count, must be a CONSTANT_Class_info structure representing an interface that is a direct superinterface of this class or interface type, in the left-to-right order given in the source for the type.

解读:
这里不存在。

2.2.11 fields_count

u2:两个字节。

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

字段表计数器,表示接下来有几个字段表。

官方说明:

The value of the fields_count item gives the number of field_info structures in the fields table. The field_info structures represent all fields, both class variables and instance variables, declared by this class or interface type.

解读:

接下来有一个字段表。

2.2.12 fields[fields_count]

field_info: 字段表结构,长度是fields_count,这里是一个。

结构如下:

field_info {
    u2             access_flags;
    u2             name_index;
    u2             descriptor_index;
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

access_flags,字段修饰符,它与类的修饰符很像都是一个 u2 的数据类型。

字段访问标识含义:

Flag NameValue含义Interpretation
ACC_PUBLIC0x0001字段是否publicDeclared public; may be accessed from outside its package.
ACC_PRIVATE0x0002字段是否privateDeclared private; usable only within the defining class.
ACC_PROTECTED0x0004字段是否protectedDeclared protected; may be accessed within subclasses.
ACC_STATIC0x0008字段是否staticDeclared static.
ACC_FINAL0x0010字段是否finalDeclared final; never directly assigned to after object construction (JLS §17.5).
ACC_VOLATILE0x0040字段是否volatileDeclared volatile; cannot be cached.
ACC_TRANSIENT0x0080字段是否transientDeclared transient; not written or read by a persistent object manager.
ACC_SYNTHETIC0x1000字段是否由编译器自动产生Declared synthetic; not present in the source code.
ACC_ENUM0x4000字段是否enumDeclared as an element of an enum.

descriptor_index,描述符,描述数据类型、方法的参数列表(包括数量、类型以及顺序)和放回值。

描述符标识字符含义:

FieldType termType含义Interpretation
Bbyte基本类型bytesigned byte
Cchar基本类型charUnicode character code point in the Basic Multilingual Plane, encoded with UTF-16
Ddouble基本类型doubledouble-precision floating-point value
Ffloat基本类型floatsingle-precision floating-point value
Iint基本类型intinteger
Jlong基本类型longlong integer
L ClassName ;reference对象类型an instance of class ClassName
Sshort基本类型shortsigned short
Zboolean基本类型booleantrue or false
[reference一个数组维度one array dimension
2.2.12.1 #1
Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000256                                              00 02
00000272   00 05 00 06 00 00
字段源码说明
access_flags00 02字段是private
name_index00 05#5 = Utf8 n字段名为 n
descriptor_index00 06#6 = Utf8 J 字段类型为 long
attributes_count00 00其他属性描述为空
attributes[attributes_count]--

解读:

  private long n;
    descriptor: J
    flags: ACC_PRIVATE

2.2.13 methods_count

u2:两个字节。

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

方法表集合计数,记录接下里将会有几个方法表集合。

官方说明:

The value of the methods_count item gives the number of method_info structures in the methods table.

解读:

接下来会有两个方法表集合。

2.2.14 methods[methods_count]

method_info:方法表结构,长度methods_count,从上文可知,两个。

结构如下:

method_info {
    u2             access_flags;
    u2             name_index;
    u2             descriptor_index;
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

access_flags,方法访问标志。
如下:

Flag NameValue含义Interpretation
ACC_PUBLIC0x0001方法是否为publicDeclared public; may be accessed from outside its package.
ACC_PRIVATE0x0002方法是否为privateDeclared private; accessible only within the defining class.
ACC_PROTECTED0x0004方法是否为protectedDeclared protected; may be accessed within subclasses.
ACC_STATIC0x0008方法是否为staticDeclared static.
ACC_FINAL0x0010方法是否为finalDeclared final; must not be overridden (§5.4.5).
ACC_SYNCHRONIZED0x0020方法是否为synchronizedDeclared synchronized; invocation is wrapped by a monitor use.
ACC_BRIDGE0x0040方法是不是由编译器产生的桥接方法A bridge method, generated by the compiler.
ACC_VARARGS0x0080方法是否接受不定参数Declared with variable number of arguments.
ACC_NATIVE0x0100方法是否为nativeDeclared native; implemented in a language other than Java.
ACC_ABSTRACT0x0400方法是否为abstractDeclared abstract; no implementation is provided.
ACC_STRICT0x0800方法是否为strictfpDeclared strictfp; floating-point mode is FP-strict.
ACC_SYNTHETIC0x1000方法是由编译器自动产生Declared synthetic; not present in the source code.

attributes,方法属性,以下是属性

AttributeLocationclass file
Codemethod_info45.3
Exceptionsmethod_info45.3
RuntimeVisibleParameterAnnotations, RuntimeInvisibleParameterAnnotationsmethod_info49.0
AnnotationDefaultmethod_info49.0
MethodParametersmethod_info52.0
SyntheticClassFile, field_info, method_info45.3
DeprecatedClassFile, field_info, method_info45.3
SignatureClassFile, field_info, method_info49.0
RuntimeVisibleAnnotations, RuntimeInvisibleAnnotationsClassFile, field_info, method_info49.0

完整属性列表:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7

2.2.14.1 #1
Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000272                            00 01 00 07 00 08 00 01
00000288   00 09 00 00 00 2F 00 01  00 01 00 00 00 05 2A B7
00000304   00 01 B1 00 00 00 02 00  0A 00 00 00 06 00 01 00
00000320   00 00 09 00 0B 00 00 00  0C 00 01 00 00 00 05 00
00000336   0C 00 0D 00 00

字段对应:

access_flagsname_indexdescriptor_indexattributes_count
00 0100 0700 0800 01
ACC_PUBLIC#7 = Utf8 <init>方法名#8 = Utf8 ()V返回类型viod有一个属性表集合

方法属性:
0x00 09, #9 = Utf8 Code,是一个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_indexu200 09#9 = Utf8 Code 表明是 Code 属性
attribute_lengthu400 00 00 2F0x2F,47个长度
max_stacku200 01操作数栈(Operand Stack)深度的最大值,1
max_localsu200 01局部变量表所需的储存空间,1个变量槽(Slot)
code_lengthu400 00 00 05方法指令长度,5 个字节

code[5]指令解读:

源码字节码含义
2Aaload_0将第一引用类型本地变量推送至栈顶
B7 00 01invokespecial #1 //Method java/lang/Object."<init>":()V调用超类构造方法,实例初始化方法,私有方法
B1return从当前方法返回 viod

exception_table_length,00 00,异常表为零。

exception_table[exception_table_length],就不存在啦。

attributes_count,方法属性表集合数,00 02,两个,如下。

00 0A
#10 = Utf8 LineNumberTable,可知是LineNumberTable属性。

LineNumberTable属性,用于描述 Java 源码行号与字节码(字节码的偏移量)之间的对应关系。

结构如下:

LineNumberTable_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 line_number_table_length;
    {   u2 start_pc;
        u2 line_number;	
    } line_number_table[line_number_table_length];
}
attribute_name_indexattribute_lengthline_number_table_length
00 0A00 00 00 0600 01
LineNumberTable6个字节长度一个

line_number_table[1]

start_pcstart_pc
00 0000 09

00 0B
#11 = Utf8 LocalVariableTable,可知是LocalVariableTable 属性。

LocalVariableTable 属性,用于描述栈帧中局部变量表的变量与 Java 源码中定义的变量之间的关系。

结构如下:

LocalVariableTable_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 local_variable_table_length;
    {   u2 start_pc;
        u2 length;
        u2 name_index;
        u2 descriptor_index;
        u2 index;
    } local_variable_table[local_variable_table_length];
}
attribute_name_indexattribute_lengthlocal_variable_table_length
00 0B00 00 00 0C00 01
LocalVariableTable 属性12个长度1个值

local_variable_table[1]

start_pclengthname_indexdescriptor_indexindex
00 0000 0500 0C00 0D00 00
05#12 = Utf8 this#13 = Utf8 Lcom/hyl/learnerJVM/classtest/ClassTest;0

start_pclength属性分别代表了整个局部变量的生命周期开始的字节码偏移量及其作用范围覆盖长度,结合起来就是局部变量在字节码之中的作用范围。

this 变量是系统默认添加进去的。

Signature 储存一个方法在字节码层面的特征签名,保存参数类型,但并不是原生类型,而是包含了参数化类型的信息。

最终整个方法解读为:

  public com.hyl.learnerJVM.classtest.ClassTest();
    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: return
      LineNumberTable:
        line 9: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/hyl/learnerJVM/classtest/ClassTest;
2.2.14.2 #2
Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000336                  00 01 00  0E 00 0F 00 01 00 09 00
00000352   00 00 31 00 04 00 01 00  00 00 07 2A B4 00 02 0A
00000368   61 AD 00 00 00 02 00 0A  00 00 00 06 00 01 00 00
00000384   00 0E 00 0B 00 00 00 0C  00 01 00 00 00 07 00 0C
00000400   00 0D 00 00

字段对应:

access_flagsname_indexdescriptor_indexattributes_count
00 0100 0E00 0F00 01
ACC_PUBLIC#14 = Utf8 inLong方法名#15 = Utf8 ()J返回类型 long有一个属性表集合

方法属性:

0x00 09, #9 = Utf8 Code,是一个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_indexu200 09#9 = Utf8 Code 表明是 Code 属性
attribute_lengthu400 00 00 310x31,49个长度
max_stacku200 04操作数栈(Operand Stack)深度的最大值,4
max_localsu200 01局部变量表所需的储存空间,1个变量槽(Slot)
code_lengthu400 00 00 07方法指令长度,7 个字节

code[7]指令解读:

源码字节码含义
2Aaload_0将第一引用类型本地变量推送至栈顶
B4 00 02getfield #2 // Field n:J获得指定类的实例域,并将其值压入栈顶
0Alconst_1将 long 类型 1 推送至栈顶
61ladd将栈顶两个 long 类型值相加并将结果压入栈顶
ADlreturn从当前方法返回 long

exception_table_length,00 00,异常表为零。

exception_table[exception_table_length],就不存在啦。

attributes_count,方法属性表集合数,00 02,两个,如下。

00 0A
#10 = Utf8 LineNumberTable,可知是LineNumberTable属性。

LineNumberTable属性,用于描述 Java 源码行号与字节码(字节码的偏移量)之间的对应关系。

结构如下:

LineNumberTable_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 line_number_table_length;
    {   u2 start_pc;
        u2 line_number; 
    } line_number_table[line_number_table_length];
}
attribute_name_indexattribute_lengthline_number_table_length
00 0A00 00 00 0600 01
LineNumberTable6个字节长度一个

line_number_table[1]

start_pcstart_pc
00 0000 0E

00 0B
#11 = Utf8 LocalVariableTable,可知是LocalVariableTable 属性。

LocalVariableTable 属性,用于描述栈帧中局部变量表的变量与 Java 源码中定义的变量之间的关系。

结构如下:

LocalVariableTable_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 local_variable_table_length;
    {   u2 start_pc;
        u2 length;
        u2 name_index;
        u2 descriptor_index;
        u2 index;
    } local_variable_table[local_variable_table_length];
}
attribute_name_indexattribute_lengthlocal_variable_table_length
00 0B00 00 00 0C00 01
LocalVariableTable 属性12个长度1个值

local_variable_table[1]

start_pclengthname_indexdescriptor_indexindex
00 0000 0700 0C00 0D00 00
07#12 = Utf8 this#13 = Utf8 Lcom/hyl/learnerJVM/classtest/ClassTest;0

start_pclength属性分别代表了整个局部变量的生命周期开始的字节码偏移量及其作用范围覆盖长度,结合起来就是局部变量在字节码之中的作用范围。

this 变量是系统默认添加进去的。

Signature 储存一个方法在字节码层面的特征签名,保存参数类型,但并不是原生类型,而是包含了参数化类型的信息。

最终整个方法解读为:

  public long inLong();
    descriptor: ()J
    flags: ACC_PUBLIC
    Code:
      stack=4, locals=1, args_size=1
         0: aload_0
         1: getfield      #2                  // Field n:J
         4: lconst_1
         5: ladd
         6: lreturn
      LineNumberTable:
        line 14: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       7     0  this   Lcom/hyl/learnerJVM/classtest/ClassTest;

2.2.15 attributes_count

u2:两个字节。

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

class属性表集合的计数,这里有一个。

官方说明:

The value of the attributes_count item gives the number of attributes in the attributes table of this class.

解读:
接下里有一个文件的属性表集合

2.2.16 attributes[attributes_count]

attribute_info:属性表结构,长度attributes_count,从上文可知,一个。

结构如下:

attribute_info {
    u2 attribute_name_index;
    u4 attribute_length;
    u1 info[attribute_length];
}

属性类型列表:

AttributeLocationclass file
SourceFileClassFile45.3
InnerClassesClassFile45.3
EnclosingMethodClassFile49.0
SourceDebugExtensionClassFile49.0
BootstrapMethodsClassFile51.0
SyntheticClassFile, field_info, method_info45.3
DeprecatedClassFile, field_info, method_info45.3
SignatureClassFile, field_info, method_info49.0
RuntimeVisibleAnnotations, RuntimeInvisibleAnnotationsClassFile, field_info, method_info49.0
2.2.16.1 #1
Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
00000400                     00 10  00 00 00 02 00 11
结构源码解释
attribute_name_index00 100x10,#16 = Utf8 SourceFile
attribute_length00 00 00 02两个字节
info[attribute_length]00 11由下图结构可知,0x11,#17 = Utf8 ClassTest.java

根据解读是SourceFile,结构如下:

SourceFile_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 sourcefile_index;
}

SourceFile属性用于记录生成这个 Class 文件的源码文件名称。

解读:

SourceFile: "ClassTest.java"

2.3 javap 工具结果

指令

javap -verbose -p ClassTest.class

结果

Classfile /D:/git/mybase/projects/github/learner-JVM/target/classes/com/hyl/le                                                                                                                                                                                                  arnerJVM/classtest/ClassTest.class
  Last modified 2020-8-7; size 414 bytes
  MD5 checksum cdd61b9867778e815b9d0b93b1412a9d
  Compiled from "ClassTest.java"
public class com.hyl.learnerJVM.classtest.ClassTest
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #4.#18         // java/lang/Object."<init>":()V
   #2 = Fieldref           #3.#19         // com/hyl/learnerJVM/classtest/Clas                                                                                                                                                                                                  sTest.n:J
   #3 = Class              #20            // com/hyl/learnerJVM/classtest/Clas                                                                                                                                                                                                  sTest
   #4 = Class              #21            // java/lang/Object
   #5 = Utf8               n
   #6 = Utf8               J
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lcom/hyl/learnerJVM/classtest/ClassTest;
  #14 = Utf8               inLong
  #15 = Utf8               ()J
  #16 = Utf8               SourceFile
  #17 = Utf8               ClassTest.java
  #18 = NameAndType        #7:#8          // "<init>":()V
  #19 = NameAndType        #5:#6          // n:J
  #20 = Utf8               com/hyl/learnerJVM/classtest/ClassTest
  #21 = Utf8               java/lang/Object
{
  private long n;
    descriptor: J
    flags: ACC_PRIVATE

  public com.hyl.learnerJVM.classtest.ClassTest();
    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: return
      LineNumberTable:
        line 9: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/hyl/learnerJVM/classtest/ClassTest;

  public long inLong();
    descriptor: ()J
    flags: ACC_PUBLIC
    Code: 
      stack=4, locals=1, args_size=1
         0: aload_0
         1: getfield      #2                  // Field n:J
         4: lconst_1
         5: ladd
         6: lreturn       
      LineNumberTable:
        line 14: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       7     0  this   Lcom/hyl/learnerJVM/classtest/ClassTest;
}
SourceFile: "ClassTest.java"

参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值