上海建设教育网站,网上做头像用什么网站,什么人适合做服装设计师,wordpress dux前言我们在开发中会遇到一些Java的执行超出我们的想象#xff0c;但是又不知道他为什么会这样执行#xff0c;这个时候我们就需要能够知道他编译后Class文件是什么样子的#xff0c;并且理解字节码的含义。Java字节码的原理进制class文件就是字节码文件#xff0c;直接是打…前言我们在开发中会遇到一些Java的执行超出我们的想象但是又不知道他为什么会这样执行这个时候我们就需要能够知道他编译后Class文件是什么样子的并且理解字节码的含义。Java字节码的原理进制class文件就是字节码文件直接是打不开打开也是乱码需要解析才能看明白里面的内容。现在存在很多语言都是允许在Jvm上比如Kotlin。 他们其实就是通过编译也编译成Jvm认识的.class 文件即可。大端和小端大端模式是指数据的高字节保存在内存的低地址中而数据的低字节保存在内存的高地址中这样的存储模式有点儿类似于把数据当作字符串顺序处理地址由小向大增加而数据从高位往低位放这和我们的阅读习惯一致。小端模式是指数据的高字节保存在内存的高地址中而数据的低字节保存在内存的低地址中这种存储模式将地址的高低和数据位权有效地结合起来高地址部分权值高低地址部分权值低。字节码文件内容组成结构Java class文件的内容结构下面解析一下一个不太好理解的结构。1. 魔数用于判断这个文件是不是class合格的文件。2. 次版本号和主板本号主板本号加次版本号用于判断这个class文件是否能被这个版本的Jvm 解析 比如jdk8的class就不能被java7版本的Jvm解析。3. 常量池个数最小是1真实的常量池个数是2个字节计算出来的数量 - 1。下面是常量池的字节码结构(u1 就是一个字节u2 就是两个字节类推)4. 类的访问控制权限补充 Acc_static 0x0008 static 修饰举个案例String[] 数组通过字节码表示是[Ljava/lang/String;5. 类的成员变量字节码格式filed_info: {u2 access_flags; -- 属性的访问类型和修饰符u2 name_index; -- 成员变量的名字指向常量池的地址u2 descriptor_index;u2 attributes_count;attribute_info attributes[attributes_count];}6. 方法的字节码格式method_info {u2 access_flags; -- 方法的访问属性和修饰符u2 name_index; -- 方法的名字指向常量池的地址u2 descriptor_index; -- 描述符字符串指向常量池地址mian方法的描述符([java/lang/String;)vu2 attributes_count; -- 对应下面的code_attributeattribute_info attributes[attributes_count];}一般一个类除了你定义的方法外还会存在两个方法clinit 和 init 处理你的静态代码和默认构造函数。方法字节码还包含code_attribute { --Code_attribute包含某个方法、实例初始化方法、类或接口初始化方法的Java虚拟机指令及相关辅助信息u2 attribute_name_index;--指向常量池名称u4 attribute_length;--后面全部的总长度u2 max_stack;--用来给出当前方法的操作数栈在方法执行的任何时间点的最大深度u2 max_locals;--用来给出分配在当前方法引用的局部变量表中的局部变量个数u4 code_length;--给出当前方法code[]数组的字节数u1 code[code_length];--给出了实现当前方法的Java虚拟机代码的实际字节内容(这些数字代码实际对应一些Java虚拟机的指令)u2 exception_table_lentgh; --异常的信息个数{u2 start_pc;--这两项的值表明了异常处理器在code[]中的有效范围即异常处理器x应满足start_pc≤x≤end_pcu2 end_pc;--start_pc必须在code[]中取值end_pc要么在code[]中取值要么等于code_length的值u2 handler_pc;--表示一个异常处理器的起点u2 catch_type;--表示当前异常处理器需要捕捉的异常类型。为0则都调用该异常处理器可用来实现finally。} exception_table[exception_table_lentgh];u2 attribute_count;--表示该方法的其它附加属性attribute_info attributes[attributes_count];--LineNumberTable、LocalVariableTable}Java方法所在行信息LineNumberTable_attribute{--被调试器用来确定源文件中由给定的行号所表示的内容对应于Java虚拟机code[] 数组的哪部分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_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];}7.类属性字节码格式attribute_info: {u2 attribute_name_index;u1 attribute_length;u1 info[attribute_length];}字节码文件解析我们一起看一下Java编译后的class文件这个是按照16进制显示的没有按照任何编码的方式进行解析过的原信息。我们按照上面字节码文件内容组成结构来解析一下这个字节码文件魔数cafe babe 就表示这个是class 文件Jvm才识别。次版本号0000主版本号0034常量池数量0021 就是2*16 1 33个常量池但是需要减一得到32个常量池。常量池信息前一个字节是tag 表示常量池的类型 oa 等于10 从常量池结构图可以找到时 constent_Methodref_info 这个类型后面读取4个字节 00 0600 1200 06 表示constent_class_info的索引项00 12 表示constent_nameAndType_info 名称和类型描述符的索引项一次解析32个常量池。特殊说明 01类型的常量池需要根据length 的长度动态解析。 比如 tag : 01 length : 0006 字符串3c69 6e69 743e。类的控制访问权限0021 表示0020加0001组合说明是...和public 。类名0005 间接引用常量池第5个常量池父类名0006 间接引用常量池第6个常量池接口数量0001 实现一个接口。接口数组0007 指向常量池 第7个常量池如果接口数量为零则不出现。成员变量数量0000 表示没有成员变量。成员变量数组如果成员变量数量为零则不占用字节。方法数量0002 两个方法方法数组0001修饰词pubilc0008方法名指向常量池0009 描述符指向常量池 0001code_attributes的数量开始解析code_attribute 000acode_attribute名称指向常量池0000 002f attribute的长度470001max_stack 操作数栈0001max_locals 局部变量个数0000 0005 code的长度 2ab7 0001 b1 code的内容就是操作虚拟机的指令信息 00 00 异常信息没有00 02表是其他附加信息有两个。开始解析LineNumberTable_attribute 00 0b指向常量池就是指的lineNumberTable00 0000 06指的是这个信息的长度00 01 line_number_table_length;00 00:start_pc ; 00 03 Java这个方法的代码行号。开始解析LocalVariableTable_attribute 00 0c额外信息的名字指向常量池00 0000 0c该信息长度00 01variable_table 信息的长度00 00start_pc00 05长度000d指向常量池局部变量描述符this00 0e指向常量池类信息描述符解析方法字节码的过程中init 方法解析完成后中间出现0000 无法解析我猜是clinit 方法的解析但是因为我们写所以使用0000 表示了。类属性数量类属性数组0001第一次属性 0010指向常量池 0000不知道 0002第二个属性 0011指向常量池。到此字节码文件全部解析完毕 中间有一点瑕疵后续学习中改进。总结字节码学习让我们了解Java底层的实现有巨大的帮助。