JVM实战与原理


目录

Class文件结构

1. 数据结构

2. class文件结构详解

2.1 魔数与Class文件的版本

2.2 常量池

2.3 访问标志

2.4 类索引、父类索引与接口索引集合

2.5 字段表集合

2.6 方法表集合

2.7 属性表集合


Class文件结构

章节目的:介绍class文件的结构


引言:当使用javac命令对java文件进行编译后,便生成了Class文件,那么Class文件的结构是怎么样的呢?

下面是Class文件结构的介绍。

1. 数据结构

首先,我们需要知道Class文件的数据结构如下,其中u1、u2、u4分别代表1个字节、2个字节、4个字节,info结尾的代表一个复合结构的数据

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];
}

2. class文件结构详解

接着,我们继续通过以下这段java代码来分析

class Person {private static String name = "wenxl";public static void main(String[] args) {System.out.println(name);}
}

对于已经编译生成了class文件,此时将class文件通过winHex打开,会有如下十六进制的字节码,例如首个CA就为一个字节,即为u1。

Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 1500000000   CA FE BA BE 00 00 00 34  00 22 0A 00 07 00 13 09   漱壕   4 "
00000016   00 14 00 15 09 00 06 00  16 0A 00 17 00 18 08 00
00000032   19 07 00 1A 07 00 1B 01  00 04 6E 61 6D 65 01 00             name
00000048   12 4C 6A 61 76 61 2F 6C  61 6E 67 2F 53 74 72 69    Ljava/lang/Stri
00000064   6E 67 3B 01 00 06 3C 69  6E 69 74 3E 01 00 03 28   ng;   <init>   (
00000080   29 56 01 00 04 43 6F 64  65 01 00 0F 4C 69 6E 65   )V   Code   Line
00000096   4E 75 6D 62 65 72 54 61  62 6C 65 01 00 04 6D 61   NumberTable   ma
00000112   69 6E 01 00 16 28 5B 4C  6A 61 76 61 2F 6C 61 6E   in   ([Ljava/lan
00000128   67 2F 53 74 72 69 6E 67  3B 29 56 01 00 08 3C 63   g/String;)V   <c
00000144   6C 69 6E 69 74 3E 01 00  0A 53 6F 75 72 63 65 46   linit>   SourceF
00000160   69 6C 65 01 00 0B 50 65  72 73 6F 6E 2E 6A 61 76   ile   Person.jav
00000176   61 0C 00 0A 00 0B 07 00  1C 0C 00 1D 00 1E 0C 00   a
00000192   08 00 09 07 00 1F 0C 00  20 00 21 01 00 05 77 65             !   we
00000208   6E 78 6C 01 00 06 50 65  72 73 6F 6E 01 00 10 6A   nxl   Person   j
00000224   61 76 61 2F 6C 61 6E 67  2F 4F 62 6A 65 63 74 01   ava/lang/Object
00000240   00 10 6A 61 76 61 2F 6C  61 6E 67 2F 53 79 73 74     java/lang/Syst
00000256   65 6D 01 00 03 6F 75 74  01 00 15 4C 6A 61 76 61   em   out   Ljava
00000272   2F 69 6F 2F 50 72 69 6E  74 53 74 72 65 61 6D 3B   /io/PrintStream;
00000288   01 00 13 6A 61 76 61 2F  69 6F 2F 50 72 69 6E 74      java/io/Print
00000304   53 74 72 65 61 6D 01 00  07 70 72 69 6E 74 6C 6E   Stream   println
00000320   01 00 15 28 4C 6A 61 76  61 2F 6C 61 6E 67 2F 53      (Ljava/lang/S
00000336   74 72 69 6E 67 3B 29 56  00 20 00 06 00 07 00 00   tring;)V
00000352   00 01 00 0A 00 08 00 09  00 00 00 03 00 00 00 0A
00000368   00 0B 00 01 00 0C 00 00  00 1D 00 01 00 01 00 00
00000384   00 05 2A B7 00 01 B1 00  00 00 01 00 0D 00 00 00     *? ?
00000400   06 00 01 00 00 00 01 00  09 00 0E 00 0F 00 01 00
00000416   0C 00 00 00 26 00 02 00  01 00 00 00 0A B2 00 02       &        ?
00000432   B2 00 03 B6 00 04 B1 00  00 00 01 00 0D 00 00 00   ? ? ?
00000448   0A 00 02 00 00 00 06 00  09 00 07 00 08 00 10 00
00000464   0B 00 01 00 0C 00 00 00  1E 00 01 00 00 00 00 00
00000480   06 12 05 B3 00 03 B1 00  00 00 01 00 0D 00 00 00      ? ?
00000496   06 00 01 00 00 00 03 00  01 00 11 00 00 00 02 00
00000512   12                                                  

2.1 魔数与Class文件的版本

ClassFile {u4             magic;u2             minor_version;u2             major_version;.......
}

对应的字节码为:CA FE BA BE 00 00 00 34

作用:每个Class文件的头4个字节称为魔数magic,作用是确定这个文件是否为JVM能接受的Clcass文件,固定为0xCAFEBABE。

后4字节说明Class文件的版本

字节码详解:00 00 00 34 说明该文件版本为JDK1.8。

2.2 常量池

ClassFile {.......u2 constant_pool_count; cp_info constant_pool[constant_pool_count-1];.......
}

对应的字节码为:00 22

作用:前两个字节说明常量池的数量,后面则是常量池内容。常量池可以理解是Class文件的资源仓库。

字节码详解:其中前两个字节0x0022转换为十进制为34,说明有33个常量

cp_info常量类型的数据结构为

cp_info {u1 tag; u1 info[];
}

其中tag的值代表当前常量属于那种常量类型

Tag Value

Constant Type

DESC DATA STRUCTURE
1 CONSTANT_Utf8 utf-8编码的字符串 CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}
3 CONSTANT_Integer 整形 CONSTANT_Integer_info {
    u1 tag;
    u4 bytes;
}
4 CONSTANT_Float 浮点型 CONSTANT_Float_info {
    u1 tag;
    u4 bytes;
}
5 CONSTANT_Long 长整形 CONSTANT_Long_info {
    u1 tag;
    u4 high_bytes;
    u4 low_bytes;
}
6 CONSTANT_Double 双精度浮点型 CONSTANT_Double_info {
    u1 tag;
    u4 high_bytes;
    u4 low_bytes;
}
7 CONSTANT_Class 类或接口的符号引用 CONSTANT_Class_info {
    u1 tag;
    u2 name_index;
}
8 CONSTANT_String 字符串类型 CONSTANT_String_info {
    u1 tag;
    u2 string_index;
}
9 CONSTANT_Fieldref 字段的符号引用 CONSTANT_Fieldref_info {
    u1 tag;
    u2 class_index;
    u2 name_and_type_index;
}
10 CONSTANT_Methodref 类中方法的符号引用 CONSTANT_Methodref_info {
    u1 tag;
    u2 class_index;
    u2 name_and_type_index;
}
11 CONSTANT_InterfaceMethodref 接口中方法的符号引用 CONSTANT_InterfaceMethodref_info {
    u1 tag;
    u2 class_index;
    u2 name_and_type_index;
}
12 CONSTANT_NameAndType 字段或方法的部分符号引用 CONSTANT_NameAndType_info {
    u1 tag;
    u2 name_index;
    u2 descriptor_index;
}
15 CONSTANT_MethodHandle 表示方法句柄 CONSTANT_MethodHandle_info {
    u1 tag;
    u1 reference_kind;
    u2 reference_index;
}
16 CONSTANT_MethodType 标识方法类型 CONSTANT_MethodType_info {
    u1 tag;
    u2 descriptor_index;
}
18 CONSTANT_InvokeDynamic 表示一个动态方法调用点 CONSTANT_InvokeDynamic_info {
    u1 tag;
    u2 bootstrap_method_attr_index;
    u2 name_and_type_index;
}

我们按字节顺序开始分析,第一个tag值为0x0A,对应常量类型为CONSTANT_Methodref,其结构为

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

对应的字节码为

0A00 0700 13

0007为class_index指向一个CONSTANT_Class_info

0013为name_and_type_index指向一个CONSTANT_NameAndType

那指向的这两个又是什么呢?我们往下继续分析

第二个tag值为0x09,对应常量类型为CONSTANT_Fieldref,其结构为

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

对应的字节码为

0900 1400 15

0014为class_index指向一个CONSTANT_Class_info

0015为name_and_type_index指向一个CONSTANT_NameAndType

我们按这样的逻辑将常量池字 节码解析为

Index Tag Info Tag Value
1 0A 0007 0013 CONSTANT_Methodref
2 09 0014 0015 CONSTANT_Fieldref
3 09 0006 0016 CONSTANT_Fieldref
4 0A 0017 0018 CONSTANT_Methodref
5 08 0019 CONSTANT_String
6 07 001A CONSTANT_Class
7 07 001B CONSTANT_Class
8 01 0004 6E6D 6561 CONSTANT_Utf8
9 01 0012 4C.. ..3B CONSTANT_Utf8
10 01 0006 3C.. ..3E CONSTANT_Utf8
11 01 0003 2829 56 CONSTANT_Utf8
12 01 0004 436F 6465 CONSTANT_Utf8
13 01 000F 4C.. ..65 CONSTANT_Utf8
14 01 0004 6D61 696E CONSTANT_Utf8
15 01 0016 28.. ..56 CONSTANT_Utf8
16 01 0008 3C.. ..3E CONSTANT_Utf8
17 01 000A 53.. ..65 CONSTANT_Utf8
18 01 000B 50.. ..61 CONSTANT_Utf8
19 0C 000A 000B CONSTANT_NameAndType
20 07 001C CONSTANT_Class
21 0C 001D 001E CONSTANT_NameAndType
22 0C 0008 0009 CONSTANT_NameAndType
23 07 001F CONSTANT_Class
24 0C 0020 0021 CONSTANT_NameAndType
25 01  0005 77.. ..6C CONSTANT_Utf8
26 01  0006 50.. ..6E CONSTANT_Utf8
27 01  0010 6A.. ..74 CONSTANT_Utf8
28 01  0010 6A.. ..6D CONSTANT_Utf8
29 01  0003 6F75 74 CONSTANT_Utf8
30 01  0015 4C.. ..3B CONSTANT_Utf8
31 01  0013 6A.. ..6D CONSTANT_Utf8
32 01  0007 70.. ..6E CONSTANT_Utf8
33 01  0015 28.. ..56 CONSTANT_Utf8

这时我们再回到第一个CONSTANT_Methodref,该常量用来描述的方法,其中

0007为class_index指向一个CONSTANT_Class_info,说明是哪个类的方法

0013为name_and_type_index指向一个CONSTANT_NameAndType,说明的是这个方法的方法名与方法的入参及返回值类型

0007即index为7的常量,我们可以看到是

7 07 001B CONSTANT_Class

CONSTANT_Class的结构为

CONSTANT_Class_info {u1 tag;u2 name_index;
}

同理,index为001B的即第27个常量是

27 01  0010 6A.. ..74 CONSTANT_Utf8

CONSTANT_Utf8的结构为

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

length为0010,即后面跟着长度为16的字符串,6A.. ..74转换为对应的字符串为java/lang/Object,说明调用的是java/lang/Object的方法

同样,0013指向第19个常量,是个CONSTANT_NameAndType_info

19 0C 000A 000B CONSTANT_NameAndType

结构如下

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

000A指向第10个常量,转换为对应的字符串为<init>,说明方法名为<init>

10 01 0006 3C.. ..3E CONSTANT_Utf8

000B指向第11个常量,转换为对应的字符串为()V,说明入参为空,返回值类型是void。

我们可以用javap -verbose Person的命令反编译,就可以得到javap工具帮我们解析的字节码描述,我们发现其中Constant pool部分与我们分析出的结果是一致的。

Classfile /D:/用户目录/我的文档/Code/JVMSearch/Person.classLast modified 2020-12-19; size 513 bytesMD5 checksum dea507ac0ecc8c9063c778c6f748a2bbCompiled from "Person.java"
class Personminor version: 0major version: 52flags: ACC_SUPER
Constant pool:#1 = Methodref          #7.#19         // java/lang/Object."<init>":()V#2 = Fieldref           #20.#21        // java/lang/System.out:Ljava/io/PrintStream;#3 = Fieldref           #6.#22         // Person.name:Ljava/lang/String;#4 = Methodref          #23.#24        // java/io/PrintStream.println:(Ljava/lang/String;)V#5 = String             #25            // wenxl#6 = Class              #26            // Person#7 = Class              #27            // java/lang/Object#8 = Utf8               name#9 = Utf8               Ljava/lang/String;#10 = Utf8               <init>#11 = Utf8               ()V#12 = Utf8               Code#13 = Utf8               LineNumberTable#14 = Utf8               main#15 = Utf8               ([Ljava/lang/String;)V#16 = Utf8               <clinit>#17 = Utf8               SourceFile#18 = Utf8               Person.java#19 = NameAndType        #10:#11        // "<init>":()V#20 = Class              #28            // java/lang/System#21 = NameAndType        #29:#30        // out:Ljava/io/PrintStream;#22 = NameAndType        #8:#9          // name:Ljava/lang/String;#23 = Class              #31            // java/io/PrintStream#24 = NameAndType        #32:#33        // println:(Ljava/lang/String;)V#25 = Utf8               wenxl#26 = Utf8               Person#27 = Utf8               java/lang/Object#28 = Utf8               java/lang/System#29 = Utf8               out#30 = Utf8               Ljava/io/PrintStream;#31 = Utf8               java/io/PrintStream#32 = Utf8               println#33 = Utf8               (Ljava/lang/String;)V
{Person();descriptor: ()Vflags:Code:stack=1, locals=1, args_size=10: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 1: 0public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=2, locals=1, args_size=10: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;3: getstatic     #3                  // Field name:Ljava/lang/String;6: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V9: returnLineNumberTable:line 6: 0line 7: 9static {};descriptor: ()Vflags: ACC_STATICCode:stack=1, locals=0, args_size=00: ldc           #5                  // String wenxl2: putstatic     #3                  // Field name:Ljava/lang/String;5: returnLineNumberTable:line 3: 0
}
SourceFile: "Person.java"

2.3 访问标志

ClassFile {.......u2             access_flags;.......
}

对应的字节码为:00 20

作用:用于识别类或者接口层次的访问信息

字节码详解:每个位所代表的意义如下表,因为该类是JDK1.2之后的编译器进行编译,且其他标识均为0,故为00 20。大家可以试试在类被声明为public,abstract,final的情况下,字节码是如何展示的。

Flag Name Value Interpretation
ACC_PUBLIC 0x0001 是否为public类型
ACC_FINAL 0x0010 是否被声明为final,只有类可设置
ACC_SUPER 0x0020 是否允许使用invokespecial字节码指令的新语意,JDK1.0.2该指令语意发生改变,故JDK1.0.2后该标志都为真
ACC_INTERFACE 0x0200 标识这是一个接口
ACC_ABSTRACT 0x0400 是否为abstract类型
ACC_SYNTHETIC 0x1000 标识这个类并非由用户代码产生
ACC_ANNOTATION 0x2000 标识这是一个注解
ACC_ENUM 0x4000 标识这是一个枚举

2.4 类索引、父类索引与接口索引集合

ClassFile {.......u2             this_class;u2             super_class;u2             interfaces_count;u2             interfaces[interfaces_count];.......
}

对应的字节码为:00 06 00 07 00 00

作用:这三项数据确定了这个类的继承关系,类索引(this_class)确定类的全限定名,父类索引(super_class)确定类的父类的全限定名,接口索引集合(interfaces)描述类实现了哪些接口

字节码详解:00 06指向常量池第6个常量,类型为CONSTACT_Class_info,值为Person。

00 07同样类型为CONSTACT_Class_info,值为java/lang/Object。

00 00说明该类没实现任何接口。好奇的同学可以试试实现了接口后,这里的字节码是如何展示的。

2.5 字段表集合

ClassFile {.......u2             fields_count;field_info     fields[fields_count];.......
}

对应的字节码为:00 01 00 0A 00 08 00 09 00 00

作用:描述接口或者类中的声明的变量。

字节码详解:

其中前两个字节0x0001转换为十进制为1,说明有1个字段。

field_info常量类型的数据结构为

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

access_flag为字段访问标志,含义表如下。字节码为00 0A,说明ACC_PRIVATE和ACC_STATIC为真,即该字段为private和static

Flag Name Value Interpretation
ACC_PUBLIC 0x0001 字段是否public
ACC_PRIVATE 0x0002 字段是否private
ACC_PROTECTED 0x0004 字段是否protected
ACC_STATIC 0x0008 字段是否static
ACC_FINAL 0x0010 字段是否final
ACC_VOLATILE 0x0040 字段是否volatile
ACC_TRANSIENT 0x0080 字段是否transient
ACC_SYNTHETIC 0x1000 字段是否由编译器自动产生的
ACC_ENUM 0x4000 字段是否enum

name_index代表字段的简单名称,descriptor_index代表字段和方法的描述符。

字节码为00 08 00 09,指向常量池第8和第9个常量,类型为CONSTACT_Utf8_info,值分别为name和Ljava/lang/String;。

说明该字段名为name,描述符为java/lang/String。

attribute_info则是该字段的属性表,字节码为00 00, 说明没有属性。

2.6 方法表集合

ClassFile {.......u2             methods_count;method_info    methods[methods_count];.......
}

对应的字节码为:00 03 00 00 00 0A 00 0B 00 01

作用:描述接口或者类中的方法。

字节码详解:

其中前两个字节0x0003转换为十进制为3,说明有3个方法。

method_info常量类型的数据结构为

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

access_flag为字段访问标志,含义表如下。字节码为00 00,说明标志均为假

Flag Name Value Interpretation
ACC_PUBLIC 0x0001 方法是否public
ACC_PRIVATE 0x0002 方法是否private
ACC_PROTECTED 0x0004 方法是否protected
ACC_STATIC 0x0008 方法是否static
ACC_FINAL 0x0010 方法是否final
ACC_SYNCHRONIZED 0x0020 方法是否synchronized
ACC_BRIDGE 0x0040 方法是否是由编译器产生的桥接方法
ACC_VARARGS 0x0080 方法是否接受不定参数
ACC_NATIVE 0x0100 方法是否native
ACC_ABSTRACT 0x0400 方法是否abstract
ACC_STRICT 0x0800 方法是否strictfp
ACC_SYNTHETIC 0x1000 方法是否是由编译器自动产生的

字节码为00 0A 00 0B,指向常量池第10和第11个常量,类型为CONSTACT_Utf8_info,值分别为<init>和()V。name_index代表方法名,descriptor_index代表方法的描述符。

说明该方法名为<init>,描述符为()V。

attribute_info则是该字段的属性表,那么属性表是什么样的结构呢。

2.7 属性表集合

ClassFile {u2             attributes_count;attribute_info attributes[attributes_count];.......
}

对应的字节码为:00 01 00 0C 00 00 00 1D

作用:Class文件、字段表、方法表都可以携带自己的属性表集合,用于描述某些场景专有的信息

字节码详解:

其中前两个字节0x0001转换为十进制为1,说明有1个属性。

attribute_info常量类型的数据结构为

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

attribute_name_index为属性名。字节码为00 0C,指向常量池第12个常量,类型为CONSTACT_Utf8_info,值为Code,说明这是一个Code属性。

00 00 00 1D说明后面属性内容的长度,1D为十进制的29,说明后面29个字节的内容为属性内容。那么这个Code属性的属性作用和结构内容是怎么样的呢?

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];
}

字节码详解:00 01 00 01 00 00 00 05 2A B7 00 01 B1 00 00 00 01 00 0D

这里从max_stack开始,max_stack描述了操作数栈深度的最大值,这里是00 01说明最大值为1

max_locals描述了局部变量表所需的存储空间,单位是Slot,对于double和long这两种64位的需要两个Slot存放,其余的byte、char、float、int、short、boolean和returnAddress等长度不超过32位的则用1个Slot存放。

Slot可以被重用,当代码执行超过局部变量的作用域,该变量占用的Slot可以被其他Slot占用,所以max_locals不等于方法用到了多少个局部变量,而是编译器根据变量的作用域计算出max_locals的大小。

code_length和code存储Java源程序编译后生成的字节码指令,code_length为00 05,说明后面有5个字节为字节码指令,为2A B7 00 01 B1,根据指令表,2A对应指令为aload_0,含义是将第0个Slot中为reference类型的本地变量推送到操作数栈顶;B7对应指令为invokespecial,作用是以栈顶的reference类型的数据所指向的对象作为方法接收者,调用对象的实例构造方法,后跟两个字节是他的参数,说明调用哪一个方法;00 01是参数,指向常量池第1个常量,类型为CONSTACT_Methodref_info,值为java/lang/Object."<init>":()V;B1对应指令为return,含义是返回此方法,且返回值为void,执行该条指令后,方法结束。

exception_table用于实现Java一场及finally处理机制,00 00说明定义了0个异常。

最后的是attribute_info,说明Code属性的属性,00 01说明有1个属性,结构是一样的。

字节码为00 0D,指向常量池第13个常量,类型为CONSTACT_Utf8_info,值为LineNumberTable,说明这是一个LineNumberTable属性。

LineNumberTable属性作用:描述Java源码行号与字节码行号之间的对应关系
LineNumberTable属性表结构

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];
}

字节码详解:00 00 00 06 00 01 00 00 00 01

00 00 00 06说明后面6个字节为属性描述。

line_number_table_length说明line_number_table长度,00 01说明后续有1个line_number_table_length。

line_number_table包含两个数据项,其中start_pc是字节码行号,line_number是Java源码行号。

00 00 00 01说明行号数据是0:1。

还有很多属性,如下。

每个属性都有不同的结构及作用,读者可以自行修改源码,从而发现不同的属性。

属性名称 使用位置 含义
Code  方法表 Java代码编译成的字节码指令
ConstantValue 字段表 final关键字定义的常量值
Deprecated 类、方法表、字段表 被声明为deprecated的方法和字段
Exceptions 方法表 方法抛出的异常
EnclosingMethod 类文件 仅当一个类为局部类或者匿名类时才能拥有这个属性,这个属性用于标识这个类所在的外围方法
InnerClasses 类文件 内部类列表
LineNumberTable Code属性 Java源码的行号与字节码指令的对应关系
LocalVariableTable Code属性 方法的局部变量描述
StackMapTable Code属性 JDK1.6新增属性,供新的类型检查验证器检查和处理目标方法的局部变量和操作数栈所需要的类型是否匹配
Signature 类、方法表、字段表 用于支持泛型情况下的方法签名
SourceFile 类文件 记录源文件名称
SourceDebugExtension 类文件 存储额外的调试信息
Synthetic 类、方法表、字段表 标识方法或字段为编译器自动生成的
LocalVariableTypeTable 使用特征签名代替描述符,是为了引入泛型语法之后能描述泛型参数化类型而添加
RuntimeVisibleAnnotations 类、方法表、字段表 为动态注解提供支持,指明哪些注解是运行时可见的
RuntimeInvisibleAnnotations 类、方法表、字段表 指明哪些注解是运行时不可见的
RuntimeVisibleParameterAnnotations 方法表 与RuntimeVisibleAnnotations类似,作用对象为方法参数
RuntimeInvisibleParameterAnnotations 方法表 与RuntimeInvisibleAnnotations类似,作用对象为方法参数
AnootationDefault 方法表 记录注解类元素的默认值
BootstrapMethods 类文件 保存invokedynamic指令引用的引导方法限定符

后面的字节码也无需在分析下去了,后面还有两个方法,一个属性,按照这个结构继续解析下去,就可以发现,跟javap反编译出来的描述是一致的。

Classfile /D:/用户目录/我的文档/Code/JVMSearch/Person.classLast modified 2020-12-19; size 513 bytesMD5 checksum dea507ac0ecc8c9063c778c6f748a2bbCompiled from "Person.java"
class Personminor version: 0major version: 52flags: ACC_SUPER
Constant pool:#1 = Methodref          #7.#19         // java/lang/Object."<init>":()V#2 = Fieldref           #20.#21        // java/lang/System.out:Ljava/io/PrintStream;#3 = Fieldref           #6.#22         // Person.name:Ljava/lang/String;#4 = Methodref          #23.#24        // java/io/PrintStream.println:(Ljava/lang/String;)V#5 = String             #25            // wenxl#6 = Class              #26            // Person#7 = Class              #27            // java/lang/Object#8 = Utf8               name#9 = Utf8               Ljava/lang/String;#10 = Utf8               <init>#11 = Utf8               ()V#12 = Utf8               Code#13 = Utf8               LineNumberTable#14 = Utf8               main#15 = Utf8               ([Ljava/lang/String;)V#16 = Utf8               <clinit>#17 = Utf8               SourceFile#18 = Utf8               Person.java#19 = NameAndType        #10:#11        // "<init>":()V#20 = Class              #28            // java/lang/System#21 = NameAndType        #29:#30        // out:Ljava/io/PrintStream;#22 = NameAndType        #8:#9          // name:Ljava/lang/String;#23 = Class              #31            // java/io/PrintStream#24 = NameAndType        #32:#33        // println:(Ljava/lang/String;)V#25 = Utf8               wenxl#26 = Utf8               Person#27 = Utf8               java/lang/Object#28 = Utf8               java/lang/System#29 = Utf8               out#30 = Utf8               Ljava/io/PrintStream;#31 = Utf8               java/io/PrintStream#32 = Utf8               println#33 = Utf8               (Ljava/lang/String;)V
{Person();descriptor: ()Vflags:Code:stack=1, locals=1, args_size=10: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 1: 0public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=2, locals=1, args_size=10: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;3: getstatic     #3                  // Field name:Ljava/lang/String;6: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V9: returnLineNumberTable:line 6: 0line 7: 9static {};descriptor: ()Vflags: ACC_STATICCode:stack=1, locals=0, args_size=00: ldc           #5                  // String wenxl2: putstatic     #3                  // Field name:Ljava/lang/String;5: returnLineNumberTable:line 3: 0
}
SourceFile: "Person.java"

JVM实战与原理---Class文件结构相关推荐

  1. JVM实战与原理--前言及索引

    JVM实战与原理 大纲 在Java入门课中,我们编写HelloWorld.java文件,用命令行运行javac后生成HelloWorld.class,之后用java命令运行HelloWorld.cla ...

  2. JVM实战与原理---类加载机制

    JVM实战与原理 目录 类加载机制 1. 类加载生命周期 1.1 加载 1.2 验证 1.3 准备 1.4 解析 1.5 初始化 2. 类加载器 类加载机制 章节目的:了解虚拟机如何加载Class文件 ...

  3. JVM实战与原理---内存回收策略

    JVM实战与原理 目录 内存回收策略 1. 堆的划分 2. 判断对象是否存活的算法介绍 2.1 引用计数算法 2.2 可达性分析算法 3. 可回收的内存区域清理的算法介绍 3.1 标记-清除算法 3. ...

  4. JVM实战与原理---字节码执行引擎

    JVM实战与原理 目录 字节码执行引擎 1. 方法区 2. 栈帧 2.1 局部变量表 2.2 操作数栈 2.3 动态连接 2.4 方法返回地址 字节码执行引擎 章节目的:虚拟机是如何找到正确的方法,如 ...

  5. JVM实战与原理---内存区域分配

    JVM实战与原理 目录 内存区域分配 1. 程序计数器 2. Java虚拟机栈 3. 本地方法栈 4. 堆 5. 方法区 6. 运行时常量池 内存区域分配 章节目的:明白虚拟机中的内存是如何划分?每块 ...

  6. 029、JVM实战总结:大厂面试题:最新的G1垃圾回收器的工作原理,你能聊聊吗

    1.ParNew + CMS的组合让我们有哪些痛点? 痛点:STW,且停顿时间不可控 G1垃圾回收器比~更好的垃圾回收性能 2.G1垃圾回收器 G1 同时回收新生代和老年代的对象,把java堆拆分为多 ...

  7. 030、JVM实战总结:G1分代回收原理深度图解:为什么回收性能比传统GC更好?

    本文是<从 0 开始带你成为JVM实战高手>内容总结,版权问题,特此声明 1.前文回顾 很多Region,新老各自对应一些Region,会在指定的系统停顿时间内,回收价值最大的Region ...

  8. JVM内存Dump原理与在线分析实战 | 得物技术

    1.前言 当前我们微服务容器化部署JVM 实例很多,常常需要进行JVM heap dump analysis,为了提升JVM 问题排查效率,得物技术保障团队研究了JVM内存Dump 原理与设计开发了J ...

  9. 开放下载!阿里云开发者学堂配套教材《JVM实战》

    简介:Java虚拟机不仅是一种跨平台的软件,而且是一种新的网络计算平台.该平台包括许多相关的技术,如符合开放接口标准的各种API.优化技术等. 在学习Java 虚拟机的时候你可能有以下疑问: Java ...

最新文章

  1. 年度书单盘点 | “裁员潮”持续蔓延?职场没有铁饭碗,只有硬技能
  2. 利用mem数组完成MM32 的 MicroPython中UART1的(REPL)的交互
  3. on条件与where条件的区别
  4. Spring MVC 4.1 支持jsonp
  5. mqtt客户端_初次接触MQTT
  6. SAP Spartacus 服务器端渲染编程规范
  7. mysql数据库子查询的使用_MySQL数据库使用子查询方式更新数据优化及思考
  8. 0x08算法设计与分析复习(二):算法设计策略-回溯法2
  9. SAP Business One助力洛德集团实现巨大商业价值
  10. 刷新table数据_关于数据透视表的刷新功能最值得了解的几个操作
  11. C++走向远洋——43(人数不定的工资类,动态分配内存与释放)
  12. html js实现分页代码,js分页代码示例
  13. 20145322何志威《网络对抗》逆向及Bof基础
  14. WinSCP显示隐藏文件
  15. activity劫持学习与复现
  16. Python开发【十一章】:RabbitMQ队列
  17. “AI+机器人”持续为多领域增“智”添“质”,开启效益增长飞轮
  18. Tanzu系列:第8部分 - 创建tkg集群
  19. 汇编指令学习(AND,OR,XOR,NOT)
  20. 【图像去噪】基于matlab小波变换(硬阙值+软阙值)图像去噪【含Matlab源码 391期】

热门文章

  1. 加载特征主数据自动删除重复关键值
  2. Mysql在字符串类型的日期上加上10分钟并和如今的日期做比較
  3. 6-11数据库mysql初始
  4. java代码示例(6-3)
  5. codefroce385E矩阵快速幂
  6. Java自定义Exception
  7. asp.net机器人注册原理
  8. mybatis 开发环境搭建
  9. getElementById 和 getElementByName的区别
  10. Anaconda3中Python3.5和Python2.7共存