由JAVA文件编译成class之后,class文件里面的结构(class结构是一个相对稳定的结构,中间没有分隔符)Class文件是一组以8个字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在文件之中,中间没有添加任何分隔符,这使得整个Class文件中存储的内容几乎全部是程序运行的必要数据,没有空隙存在。
各种不同平台的Java虚拟机,以及所有平台都统一支持的程序存储格式——字节码(Byte Code)是构成平台无关性。实现语言无关性的基础仍然是虚拟机和字节码存储格式。
基于安全方面的考虑,《Java虚拟机规范》中要求在Class文件必须应用许多强制性的语法和结构化约束,但图灵完备的字节码格式,保证了任意一门功能性语言都可以表示为一个能被Java虚拟机所接受的有效的Class文件。
内容前面必须有一个数量
无论是无符号数还是表,当需要描述同一类型但数量不定的多个数据时,经常会使用一个前置的容量计数器加若干个连续的数据项的形式,这时候称这一系列连续的某一类型的数据为某一类型的“集合”。
6.3.1 魔数与Class文件的版本
每个Class文件的头4个字节被称为魔数。
JAVA里是用的为0xCAFEBABE(咖啡宝贝、16进制)
紧接着魔数的4个字节存储的是Class文件的版本号:第5和第6个字节是次版本(MinorVersion),第7和第8个字节是主版本号(Major Version)。即使文件格式并未发生任何变化,虚拟机也必须拒绝执行超过其版本号的Class文件。
6.3.2 常量池
常量池中主要存放两大类常量:字面量(Literal)和符号引用(Symbolic References)
字面量比较接近于Java语言层面的常量概念,如文本字符串、被声明为final的常量值等。而符号引用则属于编译原理方面的概念,(com.io.student这个类,他应该在虚拟机里有一个地址,但是我们这里就是一个符号引用,我们只存入了com.io.student,从Java文件编译成class文件,是文件到文件,并不知道这个类要被装载到哪个虚拟机里,故不知道地址,只有当我们引入到虚拟机里,由符号引用转变为直接引用)
主要包括下面几类常量:
- 被模块导出或者开放的包(Package)
- 类和接口的全限定名(Fully Qualified Name)
- 字段的名称和描述符(Descriptor)
- 方法的名称和描述符
- 方法句柄和方法类型(Method Handle、Method Type、Invoke Dynamic)
- 动态调用点和动态常量(Dynamically-Computed Call Site、Dynamically-Computed Constant)
我们在开头记录了21,在常量池里,它是从0开始的,21项常量,第0项有特殊含义特殊值的,所以索引从1开始,而后面的接口字段都是从0开始。
Class文件结构中只有常量池的容量计数是从1开始,对于其他集合类型,包括接口索引集合、字段表集合、方法表集合等的容量计数都与一般习惯相同,是从0开始。
按照复杂的规则找到对应的内容(不同表,不同规则要求的不一样)
我们可以使用javap命令输出常量表,里面的值也会输出。
对内部的结构有细微的了解,并不要求掌握,只在开发语言的时候需要使用到。
参考书籍:深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)周志明