Java虚拟机 之 Class文件结构(魔数、class文件版本、常量池)[ 上 ]

魔数

魔数存在于每个Class文件的前4个字节,其实在很多文件中都存在,像jpeg在文件头中都存在魔数,其目的是为了标识文件类型。可知虚拟机区分文件类型并不是通过区分文件扩展名,而是通过魔数。

Class文件中的魔数叫做 CAFEBABE 。

做一个实验:将Hello.java的后缀名改成class,然后去执行这个class文件,看jvm是否能识别出来。

他说与class文件的魔数值是完全不同的,他的值是我划出来的,我们来看看CAFEBABE的值是多少,只需将CAFEBABE转化为10进制,他应该是34056991582才能被识别。

同样,将刚才改完扩展名的java文件用工具打开,取前4个字节转化成10进制,自然就是报错的那个数了。

Class文件版本

Class文件之所以有版本号存在,是因为虚拟机不能执行超过其版本号的Class文件,高版本的JDK可以执行低版本的Class文件,但低版本的JDK不可执行高版本的Class文件。

扫描二维码关注公众号,回复: 8728596 查看本文章

紧接着魔数的4个字节是Classs文件的版本号,其中,第5、6个字节是次版本号;第7、8个版本是主版本号。

像这样,图中我划出的标记以前是次版本号,为0;标记以后为主版本号,为34。

主版本号的34为16进制的数,所以我们需要把它转成10进制,为52。52是个什么鬼?这时候需要一个与jdk版本的对照表。

52对应这jdk1.8版本,我再去查看下我的jdk版本。

确实是1.8版本,这就呼应上了。

常量池

常量池包含着常量计数器和常量池项(cp_info)。

常量池计数器

常量池计数器是占用两个字节,0x1D的转化成十进制是29,也就是说它的常量池容量是28。这就代表着常量池中有28项常量,索引值范围是1~28,注意是从1开始计数。

为什么要把0空出来?因为有些标识不指向常量池中任何常量的项目,就可以把它指向0。

常量池项

每一个常量池项中又由一个tag(一个字节)和若干个info[]数组组成。

常量池项是记录class文件中某种类型字面量的,而决定是哪种类型的字面量,是tag值来决定的。

向下读一个字节,读出来的数是0x0A,转化成十进制是10,我们就需要知道常量池项目类型为10的常量是哪一种常量。

tag值怎么来决定哪种类型的字面量呢?这时候需要一个对照表。

从上面这张表中查到tag值为10的是CONSTANT_Methodref_info,也就是说第一个常量池是记录方法信息的一张表,这个表中有这2个字段,分别是class_index和name_and_type_index。

class_index的type为u2,所以说他有两个字节,再从字节码文件中数接下来的两个字节,所以class_index就是00 06,也就是引用了第6个常量池的位置(目前是第一个)。

接下来是name_and_type_index,也是占两个字节,再向后数两个字节00 0F。F的十进制是15,所以说它是指向了第15个常量池的位置。

以上,第一组常量就被记录完成了。

再接着读下一组常量池项,最开头还是一个tag,占一个字节,再往下数一个字节。

09 所标识的常量类型是CONSTANT_Fieldref_info,他有两个index。

先不管这两个index是干什么用的,继续向下看。0x10,所以它是指向了16号常量池的位置。

再往下数两个字节,00 11,它是指向了17号的索引位置。

至此,第二个常量池项也读完了。

再向下读一个字节的tag,08。

去查一下表,看看08是哪个表的类型。

他有一个index,向下数两个字节,0x12是指向了18号的位置。

到这第三个常量池也读完了,再后面可以读出一个utf-8的tag来,还有右边那些字符都是左边逐个字节换算过来的,有兴趣可以继续往下读。

接下来我要使用java自带的工具来看一下这个class文件了,在命令行中输入格式为[ javap -verbose 字节码文件名 ]。因为我的字节码文件叫做Hello.class,所以输入 javap -verbose Hello.class。

对照着工具和我们读出来的看:

这个工具把我们的常量池都给解析出来了,#1号位置对应着CONSTANT_Methodref_info,引用了#6和#15。

#6号位置又引用了#22号位置,再看#22号位置,它是一个utf-8,是一个java/lang/Object,所以在1#上显示着java/lang/Object。

#1号位置还引用了#15号位置。而#15号位置又引用了#7和#8,#7号是一个<init>,#8号是一个()V,所以在1#位置都有显示。

总结:首先跟据一个标志tag来查看是哪种类型的表,然后再根据表向下按字节找,表已附在下方。

参考文献

https://blog.csdn.net/wangtaomtk/article/details/52267548

http://softlab.sdut.edu.cn/blog/subaochen/2018/12/java-class文件结构:常量池/

发布了54 篇原创文章 · 获赞 4 · 访问量 9189

猜你喜欢

转载自blog.csdn.net/yichen97/article/details/102529410