路人战队|授人以鱼不如授人以渔,软妹手把手教你javap反编译分解代码( 二 )


路人战队|授人以鱼不如授人以渔,软妹手把手教你javap反编译分解代码
文章图片
常量池代表Class文件中的仓库资源 , 紧接着主次版本号之后就是常量池入口 , 由于常量池中常量的数据是不固定的 , 所以在常量池的入口放置了一项u2类型的数据 , 代表常量池容量计数值 , 从1开始 , 字节码里面是0x002d(即十进制的45个 , 代表有44项常量 , 索引值范围1~44 , 第0项空了出来 , 这样做目的在于满足后面某些指向常量池的索引值的数据在特定情况下需要表示不引用任何一个常量池项目的目的) 。
常量池主要存放两大类常量:字面量;符号引用 。
字面量接近Java语言层面的常量概念 , 如文本字符串、声名为final的常量值等;符号引用包含三类常量:类和接口的全限定名org.springframework.....Bean字段的名称和描述符private/public/protected方法的名称和描述符private/public/protected
路人战队|授人以鱼不如授人以渔,软妹手把手教你javap反编译分解代码
文章图片
u1类型表示的标志tag(1~18)代表当前这个常量属于哪种常量类型 , 如10代表了类中方法的符号引用 , 回到我们的字节码截图里面 , 他的标志位是0x0a,对应到表中就是10即此类型的常量代表一个类中方法的符号引用 。
看图哇事 , 这玩意繁琐又多 , 且都是_info结尾 , 每一项都有自己的结构 , 主要是字面量 , 和字段 , 类 , 接口方法的符号引用 , 谁都往里参合了一脚啊这是 。
路人战队|授人以鱼不如授人以渔,软妹手把手教你javap反编译分解代码
文章图片
标志位为10的CONSTANT_Methodref_info的结构
类型名称数量u1tag1u2name_index1u2name_index1复制代码name_index就是图中的index , 是一个索引值代表了这个类或者接口的全限定名 , 字节码中name_index都占2个u,的值分别是0x0009(十进制值为9) , 0x001d(十进制值为29) , 根据表可知分别是指向声明方法的类描述符以及指向名称及类型描述符的索引;
然后字节码是0x09,查表得知此9代表字段的符号引用Fieldref , 结构和CONSTANT_Methodref_info一样 , 依次推算可得到所有的44个常量的内容以及索引 。
这里借助javap看看其他的情况 , javap-verboseTestJVM
Classfile/Users/zengzhiqin/Desktop/daima/leetcode/out/production/leetcode/TestJVM.classLastmodified2020-9-20;size731bytesMD5checksum73a774d54f51805cb2319a2133c47c04Compiledfrom"TestJVM.java"publicclassTestJVMminorversion:0majorversion:52flags:ACC_PUBLIC,ACC_SUPERConstantpool:#1=Methodref#9.#29//java/lang/Object."":()V#2=Fieldref#5.#30//TestJVM.a:I#3=Fieldref#5.#31//TestJVM.b:I#4=Fieldref#32.#33//java/lang/System.out:Ljava/io/PrintStream;#5=Class#34//TestJVM#6=Methodref#5.#29//TestJVM."":()V#7=Methodref#5.#35//TestJVM.multi:()I#8=Methodref#36.#37//java/io/PrintStream.println:(I)V#9=Class#38//java/lang/Object#10=Utf8a#11=Utf8I#12=Utf8b#13=Utf8#14=Utf8()V#15=Utf8Code#16=Utf8LineNumberTable#17=Utf8LocalVariableTable#18=Utf8this#19=Utf8LTestJVM;#20=Utf8add#21=Utf8()I#22=Utf8multi#23=Utf8main#24=Utf8([Ljava/lang/String;)V#25=Utf8args#26=Utf8[Ljava/lang/String;#27=Utf8SourceFile#28=Utf8TestJVM.java#29=NameAndType#13:#14//"":()V#30=NameAndType#10:#11//a:I#31=NameAndType#12:#11//b:I#32=Class#39//java/lang/System#33=NameAndType#40:#41//out:Ljava/io/PrintStream;#34=Utf8TestJVM#35=NameAndType#22:#21//multi:()I#36=Class#42//java/io/PrintStream#37=NameAndType#43:#44//println:(I)V#38=Utf8java/lang/Object#39=Utf8java/lang/System#40=Utf8out#41=Utf8Ljava/io/PrintStream;#42=Utf8java/io/PrintStream#43=Utf8println#44=Utf8(I)V复制代码对照一下可知 , 前面两个常量和我们算到的结果一致 , 我们看到图中出现了很多I , V , 《init》,LineNumberTable等非人类能理解在代码里面也从未出现过的东西 , 这些都会被后面要说到的字段表 , 方法表 , 属性表引用到 , 用来描述一些不可名状的东西 , 不方便用固定字节表示的内容 , 例如方法的返回值是什么 , 有几个参数 , 每个参数类型是啥等等 , 也就是这些不确定的东西需要常量表的符号引用进行表达 。


推荐阅读