《深入理解JVM》第六章 类文件结构


第六章 类文件结构

框架图

高清图片地址


平台无关性:这个理想最终要实现在操作系统以上的应用层。各个不同的java虚拟机,以及所有平台都统一支持一种程序存储格式——字节码(Byte Code)是构成平台无关性的基石。

语言无关性:实现语言无关性的基础仍然是虚拟机和字节码存储格式,Java虚拟机只与”Class文件“这种特定的二进制文件格式所关联,Class文件包含了Java虚拟机指令集、符号表以及若干其他辅助信息。

Class文件:任何其他语言的实现都可以将Java虚拟机作为他们语言运行的基础,以Class文件作为他们产品的交付媒介,Java的各种信息最终都要由多条字节码指令来组合表达,所以字节码能提供的能力要大于Java,Java实现不了的不代表字节码也没法表现出来。


Class类文件的结构

介绍:这东西在第一版《Java虚拟机规范》里面就已经定义好了,那时定义的关于Class文件格式的各项细节几乎没有出现任何改变。(所以Java是可以向下兼容的。)

注意:任何一个Class文件都对应着唯一的一个类或接口的定义信息,但是,反过来说,类或接口并不一定非得都定义在文件里,有的类和接口可以动态生成,直接送入类加载器中。(所以Class文件就像他的名字,跟类和接口有关,像是把类和接口编译成了新的文件)。

基本结构

  • 是一组以8个字节为基础单位的二进制流,里面的数据项目都是紧凑排列的,中间没有任何间隔符(打开就能看到密密麻麻一片,行数不多但每行都很长)
  • 需要占用8个字节以上的时候,会按照高位在前的方式分割。(高位字节在地址最低位,低位字节在地址最高位,高位在前就是从左边开始)

具体结构
使用的是类似C语言结构体的伪结构,只有两种:”无符号数“和”表“。

  • 无符号数是基本数据类型,unsigned,用u1u2这样来表示无符号的1个字节、2个字节。
  • 表是由多个无符号数其他表作为数据项组成的复合数据结构,习惯以”info“结尾。作用是描述有层次关系的复合结构的数据,整个Class本质上也可以看作是一张表,但是这个表的数据项排序很严格,如下图,注意这里,表里的内容无论是顺序还是数量都不许变:
    (为什么固定的结构能用来表示所有的类和接口呢?或许这些字节用来存放数据已经是绰绰有余的了?答:是的,足够表示 了)

”某一类型的集合“:使用一个前置的容量计数器+若干连续的数据项的形式,来描述同一类型但数量不定的多个数据,这一系列连续的某一类型的数据伪某一类型的”集合“。

(看完了感觉就是用另一种形式表示类或接口,但是跟用java写的不一样,这里的形式很固定,编译格式都差不多,很注意字节的使用)。


魔数与Class文件的版本

魔数:Class文件的前四个字节,用来声明自己为Class文件格式,为0xCAFEBABE

版本号:紧接着魔数的就是版本号,第5、6个为次版本号,用来声明”预览版本“;第7、8为主版本号,声明Class文件版本,这个很重要,因为JDK声明了只能向下编译低版本的Class文件,不能向上编译高版本的Class文件,即使文件格式没有发生变化。(JDK无法向上兼容的原因。)

Class文件结构图

主流JDK默认和可支持的Class文件版本号


常量池

这一块很有意思,很紧凑。

位置:紧接着主次版本号之后就是常量池入口。

作用:Class文件里的资源仓库,是Class文件结构中与其他项目关联最多的数据,通常也是占空间最大的数据项目之一。

存放内容:主要两大类常量:字面量(Literal)和符号引用(Symbolic References)。字面量接近java语言层面的常量概念,如字符串,被final声明的常量值;符号引用是一些编译原理方面的东西。

特点:Class文件中不会保存信息的内存布局,所以不经过虚拟机的转换是找不到真正的内存入口地址的,也不能直接被虚拟机使用,只有虚拟机做了类加载之后,才可以解析、翻译,得到具体的内存地址。

参考

参数
下面都是按照顺序来的:

  • 0x0016:第一个,类型为u2,代表容量计数器,有多少个常量,不过要注意这里是从1开始的,0位置拿出来干别的了,比如说上面的0x0016,十进制就是22,说明有21个常量,索引为1-21,第0项是为那些“不引用任何一个常量池项目”的数据项准备的。索引从1开始的就这一个。
  • 0x007:常量池中的每一个常量都是一个表,而这个表里又有17种不同类型的常量,所以为了区分是哪一种类型,表结构的第一个位置是个u1类型的标志位,用来表示当前常量属于哪种常量类型。如上图,下一个位置是0x007,查表就是CONSTANT_Class_info类型,这个类型的常量代表一个类或者接口的符号引用。下面配上CONSTANT_Class_info的结构:
  • 0x000:tag是标志位,用于区分常量类型(类型不是在上一位就已经确定了吗?不过这里为0,又是什么意思呢?)
  • 0x002:name_index是常量池的索引值,指向常量池中一个CONSTANT_Utf8_info类型常量(怎么指定的,这个类型的索引是1啊,上面用07找到了对应的Class_info,说明就是从1开始的),值为0x002,即常量池的第二项常量。(常量表中包含别的常量表?)(我感觉这里要么是说错了,要么是写错了,说错在于自身不知道name_index指向的类型,写错在于tag应是标注后面的类型的,应为1,而不是0)
  • 0x001:这是第二个常量的标志为,查表可知为CONSTANT_Utf8_info类型,对应上面那个常量指向的,对应的结构如下:
  • 0x000:标志位,tag又为0,应该就是没有引用的意思?
  • 0x001D:length,说明这个字符串是多少字节,后面紧跟的是长度为length的数据,是使用UTF-8缩略编码表示的数据。0x001D为10进制的29,所以后面29个字节都是该类型的内容,在这里为“org/fenixsoft/clazz/TestClass”。另外,要注意,名称一般都要引用这个类型,长度不能超过65535字节。

工具:javap,专门用来分析Class字节码,其中会生成一些源代码中不存在的常量,这些都是编译器自动生成的。

常量池的项目类型

剩的没看,也不知道有啥用,等以后吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值