JVM之.class文件和字节码解析

java源码

注意有两个静态属性
在这里插入图片描述

.class字节码

用notepad++打开,需要安装一个HEX-Editor插件。这里有个小坑,必须是装32位的notepad,然后打开用插件下面的HEX-Edito—>View in HEx就好了!
或者用editplus,notepad++复制出来格式不对。最好用这个
在这里插入图片描述

解析流程

字节码文件解析流程图,从上到小解析就好了
其实解析字节码就想摩斯密码一样,有一个对应的密码本。对照着就可以解析了。具体可以看书《JVM虚拟机规范》

u1的意思是: 占1个字节 (16进制的一个字节占两位00)
u2的意思是: 占2个字节
u4的意思是: 占4个字节
!的意思是:不确定,是动态计算的
在这里插入图片描述

开始解析

首先说下:上面的字节码都是16进制的,需要计算成10进制的,其次可以看到分成三部分,左边address部分和右边dump部分是没有用的,我们直接解析中间的。还有并不是一排表示一个东西。最后我会把我解析的这个类的信息贴出来。

魔数

ca fe ba be:魔术,表示是一个合格的class文件

为什么会有魔数?魔数有什么用?
其实就是JVM判断是不是一个合格的class文件,如果是就继续往下面读

次版本号和主版本号是指java版本的版本号,看图

00 00:次版本号。这个没啥好解释的把
00 34:主版本号 (3*15+4=52)= jdk1.8
在这里插入图片描述

解析常量池

constant_pool_count是常量池大小

00 20 =32。这里需要注意常量池是从1开始的,所以要减一,理论上是32个,实际是31个。具百度说,0是null。看图验证:工具是jclasslib,idea的插件
在这里插入图片描述

常量池解析

常量池选项属性图。 下面有些属性我有解释,但是具体的解释最好还是看虚拟机规范
在这里插入图片描述

第一个常量池

	Methodref_info {
		u1 tag; 0A=10
		u2 class_index;  00 05  指向常量池5
		u2 name_and_type_index; 00 1A   它表示当前字段或方法的名字和描述符
	}

第二个常量池,后面一样的我就不解释了

	Fieldref_info {
	u1 tag; 09
	u2 class_index; 00 04
	u2 name_and_type_index; 00 1B   
}	

第三个常量池

	Fieldref_info {
	u1 tag; 09
	u2 class_index; 00 04
	u2 name_and_type_index; 00 1C 
}	

在这里插入图片描述

…后面的我就省略了,一样的
在这里插入图片描述

access_flags 类修饰符

00 21 = public 和 super

this_class 当前类

00 04 指向常量池,当前类
在这里插入图片描述

super_class

00 05 指向常量池,父类

interfaces_count :实现的接口数量

00 00 :0那么就跳过interfaces[]

fields_count

00 02 表示该类或接口声明的类字段或者实例字段个数,说白了就是你的成员变量有几个

	fields_info[
		field_info {
				u2 access_flags; 00 08  access_flags 项的值是用于定义字段被访问权限和基础属性的掩码标志 请对表
				u2 name_index; 00 06	指向常量池
				u2 descriptor_index; 00 07  描述符
				u2 attributes_count; 00 00
				attribute_info attributes[attributes_count];  就是如果上面哪个count不为0,这里又是一个数组
			}
		field_info {
				u2 access_flags; 00  08 
				u2 name_index; 00 08
				u2 descriptor_index; 00 07
				u2 attributes_count; 00 00
				attribute_info attributes[attributes_count];
			}

]

methods_count

00 03 =3个方法个数 应该会好奇为啥会是三个哈?我这明明只写了一个。因为我本身main有一个,构造函数有一个,clint也是一个。clint这个方法是动态生成的,如果类中有静态属性或者静态块就会生成这个方法

解析方法,最难的

methods_info[
	method_info {
		u2 access_flags; 00 01 access_flags 项的值是用于定义当前方法的访问权限和基本属性的掩码标志
		u2 name_index; 00 09 指向常量池
		u2 descriptor_index; 00 0A 方法描述符 V代表返回值是void 其他跟字段描述符一样
		u2 attributes_count; 00 01 code属性个数
		attribute_info attributes[attributes_count];
		attributes[
			Code_attribute {
					u2 attribute_name_index; 00 0B  指向常量池,表示字符串code
					u4 attribute_length; 00 00 00 2F attribute_length这个意思是下面所有的字节数加起来是这个数;attribute_length 项的值表示当前属性的长度,不包括开始的 6 个字节
					u2 max_stack; 00 01  操作栈数量,是栈帧里面的 在任意时刻,操作数栈都会有一个确定的栈深度,一个 long 或者 double 类型的数据会占用两个单位的栈深度,其他数据类型则会占用一个单位深度
					u2 max_locals; 00 01 max_locals 项的值给出了分配在当前方法引用的局部变量表中的局部变量个数
					u4 code_length; 00 00 00 05  code_length 项给出了当前方法的 code[]数组的字节数
					u1 code[code_length]; 2A  B7 00 01 B1 code[]数组给出了实现当前方法的 Java 虚拟机字节码---方法体或者说是字节码指令
					u2 exception_table_length; 00 00  异常
					{  u2 start_pc;
					u2 end_pc;
					u2 handler_pc;
					u2 catch_type;
					} exception_table[exception_table_length];
					u2 attributes_count; 00 02 表示attributes数组的个数
					attribute_info attributes[attributes_count];
					attributes[
						LineNumberTable_attribute {  为什么我知道是这个属性勒?因为00 0C指向常量池12,而12就是LineNumberTable_attribute。
								u2 attribute_name_index;  00 0C
								u4 attribute_length; 00 00 00 06  attribute_length 给出了当前属性的长度,不包括开始的 6 个字节
								u2 line_number_table_length; 00 01  说明line_number_table数组的个数,而line_number_table里的元素就是下面的这个{}
								line_number_table[line_number_table_length];
								[
									{  
										u2 start_pc;  00 00  code数组的索引
									   u2 line_number;  00 08  line_number 项的值必须与源文件的行数相匹配
									}
								]
							}
						LocalVariableTable_attribute {
								u2 attribute_name_index; 00 0D     指向常量池
								u4 attribute_length; 00 00 00 0c   当前属性的长度,不包括开始的 6 个字节
								u2 local_variable_table_length;	00 01   local_variable_table[]数组的成员个数
								local_variable_table[local_variable_table_length];
								[
									{  
										u2 start_pc; 00 00  start_pc是local_variable_table的下标
										u2 length;  00 05	length两种意思。具体的看书
										u2 name_index; 00 0E 指向常量池,表示一个局部变量的有效的非全限定名
										u2 descriptor_index; 00 0F 字段描述符
										u2 index;  00 00 	index为此局部变量在当前栈帧的局部变量表中的索引
									}
								] 
							}
					
					]
				}
		]	
	}


method_info {
		u2 access_flags; 00 09 public static 修饰符 可以相加的
		u2 name_index;  00 10
		u2 descriptor_index; 00 11
		u2 attributes_count; 00 03
		attribute_info attributes[attributes_count];
		attributes[
			Code_attribute {
					u2 attribute_name_index; 00 0B  指向常量池,表示字符串code
					u4 attribute_length; 00 00 00 2B attribute_length这个意思是下面所有的字节数加起来是这个数;attribute_length 项的值表示当前属性的长度,不包括开始的 6 个字节
					u2 max_stack;  00 00  操作栈数量,是栈帧里面的 在任意时刻,操作数栈都会有一个确定的栈深度,一个 long 或者 double 类型的数据会占用两个单位的栈深度,其他数据类型则会占用一个单位深度
					u2 max_locals;  00 01 max_locals 项的值给出了分配在当前方法引用的局部变量表中的局部变量个数
					u4 code_length; 00 00 00 01  code_length 项给出了当前方法的 下面的code[]数组的字节数
					u1 code[code_length]; B1 code[]数组给出了实现当前方法的 Java 虚拟机字节码---方法体或者说是字节码指令
					u2 exception_table_length; 00 00  异常
					{  u2 start_pc;
					u2 end_pc;
					u2 handler_pc;
					u2 catch_type;
					} exception_table[exception_table_length];
					u2 attributes_count; 00 02 表示attributes数组的个数
					attribute_info attributes[attributes_count];
					attributes[
						LineNumberTable_attribute {  为什么我知道是这个属性勒?因为00 0C指向常量池12,而12就是LineNumberTable_attribute。
								u2 attribute_name_index;  00 0C
								u4 attribute_length; 00 00 00 06  attribute_length 给出了当前属性的长度,不包括开始的 6 个字节
								u2 line_number_table_length; 00 01  说明line_number_table数组的个数,而line_number_table里的元素就是下面的这个{}
								line_number_table[line_number_table_length];
								[
									{  
										u2 start_pc;  00 00  code数组的索引
									   u2 line_number;  00 10  line_number 项的值必须与源文件的行数相匹配
									}
								]
							}
						LocalVariableTable_attribute {
								u2 attribute_name_index; 00 0D     指向常量池
								u4 attribute_length; 00 00 00 0c   当前属性的长度,不包括开始的 6 个字节
								u2 local_variable_table_length;	00 01   local_variable_table[]数组的成员个数
								local_variable_table[local_variable_table_length];
								[
									{  
										u2 start_pc; 00 00  start_pc是local_variable_table的下标
										u2 length;  00 01	length两种意思。具体的看书
										u2 name_index; 00 12 指向常量池,表示一个局部变量的有效的非全限定名
										u2 descriptor_index; 00 13 字段描述符
										u2 index;  00 00 	index为此局部变量在当前栈帧的局部变量表中的索引
									}
								] 
							}
					
					]
				},
				Exceptions_attribute {
					u2 attribute_name_index; 00  14 指向常量池20,代表字符串exceptions
					u4 attribute_length; 00 00 00 04 attribute_length 项的值给出了当前属性的长度,不包括开始的 6 个字节
					u2 number_of_exceptions; 00 01  exception_index_table数组成员个数
					u2 exception_index_table[number_of_exceptions]; 
						[
							Class_info {
								u1 tag; 默认等于00 07 
								u2 name_index; 00 15 指向常量池
							}
						]
				},
				{ 这个属性我没找到 methodParamters
				00 16 00 00 00 05 01  00 12 00 00属于methodparameters
				}
				
		]
	}

method_info { 第三个不解析了太累了
		u2 access_flags;
		u2 name_index;
		u2 descriptor_index;
		u2 attributes_count;
		attribute_info attributes[attributes_count];
	}

]

方法解析完

在这里插入图片描述

attributes_count

00 01 类属性

attributes[attributes_count] = attributes[1]
	[
		SourceFile_attribute  {
			u2 attribute_name_index;  00 18
			u4 attribute_length; 00 00 00 02
			u1 sourcefile_index; 00 19
			}
	]

一些需要用到对应表,最好看书,详细

字段描述符图

在这里插入图片描述

类和属性访问修饰符图,这个数可以相加,比如0x0009就是public static

在这里插入图片描述

下面是一些解析的时候一些属性集合

field_info

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

method_info

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

attribute_info

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

Code_attribute

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

LineNumberTable_attribute

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

LocalVariableTable

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

SourceFile_attribute

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

Java虚拟机规范pdf带目录地址

Java虚拟机规范pdf带目录

猜你喜欢

转载自blog.csdn.net/weixin_42812986/article/details/107876683