解析java字节码
java字节码划分区域

图中u4、u2等表示的是字节u4就是4个字节u2就是2个字节以此类推
idea查看class的十六进制的方式
看这里 https://blog.csdn.net/weixin_45112292/article/details/115609491
开始分析准备解析
其中魔术就是magic它表示的是字节码的开头CAFEBABE这个单词
然后次版本号也就是minor version
然后主版本号majorversion
然后常量池。。。现在应该会看图了后面的不写了
对应的次版本号与主版本号

然后常量池类型图 先看一个简陋的图

描述符
* byte B // 这个B就是描述符 描述的是byte类型 下面都是同理
* char C
* short S
* int I
* float F
* long J 注意,不是L
* double D
* void V
*
* 引用类型 Ljava/lang/StringLjava/lang/String; 这个引用类型是L
* 数组 [[[[I => 一维int类型的数组 数组是[ 一个[是一维数组两个是二维数组也就是[[这样N
* 维数组就是N个[
*
* [Ljava/lang/String; 这样就表示一个String类型的数组 String[] 这样的
描述符图

修饰符的标记

大端小端 就是数据在内存中的样子可能是反着的

描述的列值为1 这个下面看字节码

上面字节码对应的代码
public class Am {
public static void main(String[] args) {
System.out.println("我是狗 我是狗");
}
}
然后开始根据字节码获取它的常量池 字节码是十六进制的
首先字节码的前八个数也就是CA FE BA BE 00 00 00 34
CA FE BA BE是魔术
00 00 是次版本号
00 34是主版本号 翻译成十进制就是52是jdk1.8
然后有两个字节的常量池大小 也就是00 22 表示常量池大小是44(22的十进制是44)如果不确定可以下载idea的插件jclasslib进行查看 jclasslib显示的常量池是33个它不显示第0个位置上的当前主流解释第0个位置是存放的this
然后我们开始读取常量池常量池的大小用两个字节表示然后是0A 十进制的是10 也就是找常量池值为10的也就是
CONSTANT_Methodref_info它的作用就是指向类的全限定名最终会指向CONSTANT_Utf8_info这
个会记录一个字符串这个字符串就是全类名我这里的是<java/lang/Object>这个Object的
然后CONSTANT_Methodref_info还会指向字段或方法名与方法的描述符或字段的描述符 描述符据图的参考上面的前置知识常量池类型图
然后后面00 06这里就表示读取第六个常量池中的值这个00 06就是符号引用它会用#6表示

上图是用jclasslib看到的可以跟字节码对应上
然后读取00 14 十进制就是20 表示的是方法名 与 返回值 与参数
参数是() 表示没有参数 、
V 表示返回值 这里的是void
init 方法名
然后第一个常量池就解析完了 然后就是下一个这时读取两个字节也就是09 看上面的图既可以明白后面的常量池也是很第一个一样的套路 看看上面常量池类型的图中的介绍就懂了
然后解析一个方法

从选中的00 07开始就是方法了它前面的00 01是方法的访问权限public为1private为2 再前面的00 02是成员方法的个数 成员属性的也跟它同理
通过jclasslib找到的

然后先看方法在字节码中的布局
这是字段

这是方法

方法与属性中的数据类型





从这开始上面是前置知识 前置知识还有个进制 class使用十六进制编码不懂进制百度一下
00 07是方法的名字
00 08是方法的参数返回值等信息
后面是00 01是对应的attributes_count这个表示有一个attributes(attributes表示一个属性)然后后面是00 09这时就进入Code_attribute中了00 09对应Code_attribute中的attributes_name_index然后它指向的是第九个常量池
然后

对应的就是code
然后往后读就是u4也就是读取4个字节也就是 00 00 00 2F转换为十进制就是47

jclasslib中也是47很显然这不是巧合 然后就表示后面47个字节都是code的也就是对应Code_attribute的attribute_length然后继续往下00 001表示栈的深度这里是1对应Code_attribute中的max_stack然后继续往后读00 01对应Code_attribute的max_locals表示局部变量表的深度在这里是1
然后读取4个字节00 00 00 05这里对应字节码指令的长度
2A B7 00 01 B1这5个
2A是指令名字

2A B7 00 01 B1
这个00 01表示操作数这里操作的是#1

就是调用初始化方法

B7与B1可以理解为开始与结束
然后往后读两个字节是
00 00 表示异常数这里是0 这里对应exception_table_length
然后往后读是 00 02这里表示一个属性的长度对应attributes_count
然后读取两个字节是00 0A 十进制就是10然后找第十个常量池

是LineNumberTable 这个LineNumberTable是用来记录行号的 00 0A就以及进入LineNumberTable的结构了00 0A表示的是attribute_name_index
然后它的结构上面有
然后进入LineNumberTable_attribute中
读取四个字节
长度是00 00 00 06 这个好像没有用
然后又是两个字节长度
00 01对应attribute_name_index
然后是 00 00 对应的谁看下图

然后是 00 01 对应的谁看下图 line_number是java代码的行号的索引

jclasslib中

然后继续往后读是 00 0B 对应的是LocalVariableTable(局部变量表)

往后读4字节00 00 00 0C转为十进制是12 这个表示的是局部变量表的长度
jclasslib中

然后再读取两个字节 00 01 是local_variable_table_length 局部变量的长度 这里的局部变量是this
往后读就是00 00 对应start_pc
往后读就是 00 05 对应length
start_pc与length之间称为变量的作用域 这是0-5

init代码是0-4也就是执行完return 这个this就无效了

然后继续往后读两个字节00 0C

这里是this然后往后读两个字节00 0D转为十进制就是13 然后指向第13个常量池

jclasslib中的结果

到这字节码就解析完了 通过步骤跟上面的图做对比就能全明白了
上面的步骤只解析了常量池与init方法其他方法也是跟init解析方式一样
套着上面图中的描述一步一步的走就可以