1 无关性的基石
java虚拟机和Class文件的存在带来了两种宝贵的特性:
-
向上:语言无关性:
- 只要是满足《Java虚拟机规范》中对Class文件的规范要求,无论此Class文件是通过何种方式何种语言得来的,都可以放到jvm上运行。
-
向下:平台无关性:
- 不同操作系统的java虚拟机对开发者屏蔽了平台的底层实现,但都同时接收并允许.Class字节码文件。
2 Class类文件的结构
-
Class文件是以8个字节为基础单位的二进制流,其中各个数据项目按顺序排列,没有分隔符,几乎全部是程序运行必要的数据,没有空隙存在。当需要占用8个字节以上的空间时,数据会按高位在前(按读取顺序先读的为低位,后读的为高位)的方式分割成8个字节的块进行存储。
-
Class文件格式采用类似于C语言结构体的伪结构来存储数据,主要包括两种数据类型:“无符号数"和"表”。
- 无符号数:用u1、u2、u4、u8分别表示1个字节、2个字节、4个字节和8个字节的无符号数,用于描述数字、索引引用、数量值或UTF-8编码的字符串值。
- 表:由多个无符号数或其他表组成的复合数据类型,表的命名通常以"_info"结尾,用于描述有层次关系的复合结构的数据。
-
Class文件本身可以被视为一张表,由表6-1中的数据项按照严格的顺序排列构成。这些数据项包括Class文件的各个组成部分,如魔数、版本信息、常量池、访问标志等。
-
数据项中可能需要描述同一类型但数量不定的多个数据时,通常会使用容量计数器和连续的数据项,这些连续的数据项构成了该类型的集合。
2.1 魔数与Class文件的版本
-
定义与目的:每个Class文件头4个字节的魔数用于确认文件是否为一个能被Java虚拟机接受的Class文件。
-
Class文件的魔数值:0xCAFEBABE,被选中因其独特性和易于记忆的特点。
-
历史背景:这个魔数值在Java被称为“Oak”语言时(约1991年)确定。它象征着Peet’s Coffee的Baristas咖啡,反映了Java开发团队的创意。
-
Class文件版本号:
-
组成:紧接魔数后的4个字节,包括次版本号(2字节)和主版本号(2字节)。
-
版本号起始:从45.0开始,自jdk 1.1之后每个大的JDK版本发布,主版本号加1。
-
兼容性:高版本JDK能向下兼容旧版本Class文件,但不能运行新版本的Class文件。
-
次版本号:在JDK 1.2之前被短暂使用,JDK 1.0.2支持的版本45.0~ 45.3,JDK 1.1支持版本45.0~45.65535。在JDK 1.2之后到JDK 12之前,次版本号未使用,固定为0。JDK 12开始,次版本号用于标识“技术预览版”功能特性的支持。如果Class文件使用了预览功能,则次版本号标识为65535,以便JVM能区分。
-
2.2 常量池
-
作用:常量池主要作为Class文件的资源仓库,存放着各种字面量和符号引用。
-
表类型数据:是Class文件中第一个出现的表类型数据项目。
-
常量池容量计数值(constant_pool_count):
- u2类型
- 从1而不是0开始
- 特殊考虑:第0项常量空出来,允许某些索引值在特定情况下表示“不引用任何一个常量池项目”。
-
内容:
-
字面量:比如文本字符串、被声明为
final
的常量值等,接近于Java语言层面的常量概念。 -
符号引用:编译原理概念,包括:
-
被模块导出或者开放的包(Package)
-
类和接口的全限定名(Fully Qualified Name)
-
字段的名称和描述符(Descriptor)
-
方法的名称和描述符
-
方法句柄和方法类型(Method Handle、Method Type、Invoke Dynamic)
-
动态调用点和动态常量(Dynamically-Computed Call Site、Dynamically-Computed Constant)
当虚拟机做类加载时,将会从常量池获得对应的符号引用,再在类创建时或运行时解析、翻译到具体的内存地址之中。
-
-
-
常量的结构:
-
共同点:
-
常量池中每一项常量都是一个表
-
表结构起始的第一位都是个u1类型的标志位
-
2.3 访问标志
在常量池结束之后,紧接着的2个字节代表访问标志(access_flags),这个标志用于识别一些类或者接口层次的访问信息。具体的标志位以及标志的含义见表6-7。
access_flags中一共有16种标志可以使用,当前只定义了其中9个,没有使用到的标志位要求一 律为零。